Skip to contentSkip to conversation

readahead stats/tracing, backwards prefetching and more

PATCH In review Wu Fengguang 11 participants 49 messages Nov 21, 2011 – Nov 30, 2011

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

cover readahead stats/tracing, backwards prefetching and more

Andrew,

I'm getting around to pick up the readahead works again :-)

This first series is mainly to add some debug facilities, to support the long missed backwards prefetching capability, and some old patches that somehow get delayed (shame me).

The next step would be to better handle the readahead thrashing situations. That would require rewriting part of the algorithms, this is why I'd like to keep the backwards prefetching simple and stupid for now.

When (almost) free of readahead thrashing, we'll be in a good position to lift the default readahead size. Which I suspect would be the single most efficient way to improve performance for the large volumes of casually maintained Linux file servers.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw

PATCH 1/8 block: limit default readahead size for small devices

Linus reports a _really_ small & slow (505kB, 15kB/s) USB device, on which blkid runs unpleasantly slow. He manages to optimize the blkid reads down to 1kB+16kB, but still kernel read-ahead turns it into 48kB.

lseek 0, read 1024 => readahead 4 pages (start of file)
lseek 1536, read 16384 => readahead 8 pages (page contiguous)

The readahead heuristics involved here are reasonable ones in general. So it's good to fix blkid with fadvise(RANDOM), as Linus already did.

For the kernel part, Linus suggests:
So maybe we could be less aggressive about read-ahead when the size of the device is small? Turning a 16kB read into a 64kB one is a big deal, when it's about 15% of the whole device!

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

        disk size    readahead size
     (scale by 4)      (scale by 2)
               1M                8k
               4M               16k
              16M               32k
              64M               64k
             256M              128k
        --------------------------- (*)
               1G              256k
               4G              512k
              16G             1024k
              64G             2048k
             256G             4096k

(*) Since the default readahead size is 128k, this limit only takes effect for devices whose size is less than 256M.

The formula is determined on the following data, collected by script:

	#!/bin/sh

	# please make sure BDEV is not mounted or opened by others
	BDEV=sdb

	for rasize in 4 16 32 64 128 256 512 1024 2048 4096 8192
	do
		echo $rasize > /sys/block/$BDEV/queue/read_ahead_kb
		time dd if=/dev/$BDEV of=/dev/null bs=4k count=102400
	done

The principle is, the formula shall not limit readahead size to such a degree that will impact some device's sequential read performance.

The Intel SSD is special in that its throughput increases steadily with larger readahead size. However it may take years for Linux to increase its default readahead size to 2MB, so we don't take it seriously in the formula.

SSD 80G Intel x25-M SSDSA2M080 (reported by Li Shaohua)

	rasize	1st run		2nd run
	----------------------------------
	  4k	123 MB/s	122 MB/s
	 16k  	153 MB/s	153 MB/s
	 32k	161 MB/s	162 MB/s
	 64k	167 MB/s	168 MB/s
	128k	197 MB/s	197 MB/s
	256k	217 MB/s	217 MB/s
	512k	238 MB/s	234 MB/s
	  1M	251 MB/s	248 MB/s
	  2M	259 MB/s	257 MB/s
==>	  4M	269 MB/s	264 MB/s
	  8M	266 MB/s	266 MB/s

Note that ==> points to the readahead size that yields plateau throughput.

SSD 22G MARVELL SD88SA02 MP1F (reported by Jens Axboe)

	rasize  1st             2nd
	--------------------------------
	  4k     41 MB/s         41 MB/s
	 16k     85 MB/s         81 MB/s
	 32k    102 MB/s        109 MB/s
	 64k    125 MB/s        144 MB/s
	128k    183 MB/s        185 MB/s
	256k    216 MB/s        216 MB/s
	512k    216 MB/s        236 MB/s
	1024k   251 MB/s        252 MB/s
	  2M    258 MB/s        258 MB/s
==>       4M    266 MB/s        266 MB/s
	  8M    266 MB/s        266 MB/s

SSD 30G SanDisk SATA 5000

	  4k	29.6 MB/s	29.6 MB/s	29.6 MB/s
	 16k	52.1 MB/s	52.1 MB/s	52.1 MB/s
	 32k	61.5 MB/s	61.5 MB/s	61.5 MB/s
	 64k	67.2 MB/s	67.2 MB/s	67.1 MB/s
	128k	71.4 MB/s	71.3 MB/s	71.4 MB/s
	256k	73.4 MB/s	73.4 MB/s	73.3 MB/s
==>	512k	74.6 MB/s	74.6 MB/s	74.6 MB/s
	  1M	74.7 MB/s	74.6 MB/s	74.7 MB/s
	  2M	76.1 MB/s	74.6 MB/s	74.6 MB/s

USB stick 32G Teclast CoolFlash idVendor=1307, idProduct=0165

	  4k	7.9 MB/s 	7.9 MB/s 	7.9 MB/s
	 16k	17.9 MB/s	17.9 MB/s	17.9 MB/s
	 32k	24.5 MB/s	24.5 MB/s	24.5 MB/s
	 64k	28.7 MB/s	28.7 MB/s	28.7 MB/s
	128k	28.8 MB/s	28.9 MB/s	28.9 MB/s
==>	256k	30.5 MB/s	30.5 MB/s	30.5 MB/s
	512k	30.9 MB/s	31.0 MB/s	30.9 MB/s
	  1M	31.0 MB/s	30.9 MB/s	30.9 MB/s
	  2M	30.9 MB/s	30.9 MB/s	30.9 MB/s

USB stick 4G SanDisk Cruzer idVendor=0781, idProduct=5151

	  4k	6.4 MB/s 	6.4 MB/s 	6.4 MB/s
	 16k	13.4 MB/s	13.4 MB/s	13.2 MB/s
	 32k	17.8 MB/s	17.9 MB/s	17.8 MB/s
	 64k	21.3 MB/s	21.3 MB/s	21.2 MB/s
	128k	21.4 MB/s	21.4 MB/s	21.4 MB/s
==>	256k	23.3 MB/s	23.2 MB/s	23.2 MB/s
	512k	23.3 MB/s	23.8 MB/s	23.4 MB/s
	  1M	23.8 MB/s	23.4 MB/s	23.3 MB/s
	  2M	23.4 MB/s	23.2 MB/s	23.4 MB/s

USB stick 2G idVendor=0204, idProduct=6025 SerialNumber: 08082005000113

	  4k	6.7 MB/s 	6.9 MB/s 	6.7 MB/s
	 16k	11.7 MB/s	11.7 MB/s	11.7 MB/s
	 32k	12.4 MB/s	12.4 MB/s	12.4 MB/s
   	 64k	13.4 MB/s	13.4 MB/s	13.4 MB/s
	128k	13.4 MB/s	13.4 MB/s	13.4 MB/s
==>	256k	13.6 MB/s	13.6 MB/s	13.6 MB/s
	512k	13.7 MB/s	13.7 MB/s	13.7 MB/s
	  1M	13.7 MB/s	13.7 MB/s	13.7 MB/s
	  2M	13.7 MB/s	13.7 MB/s	13.7 MB/s

64 MB, USB full speed (collected by Clemens Ladisch)
Bus 003 Device 003: ID 08ec:0011 M-Systems Flash Disk Pioneers DiskOnKey

	4KB:    139.339 s, 376 kB/s
	16KB:   81.0427 s, 647 kB/s
	32KB:   71.8513 s, 730 kB/s
==>	64KB:   67.3872 s, 778 kB/s
	128KB:  67.5434 s, 776 kB/s
	256KB:  65.9019 s, 796 kB/s
	512KB:  66.2282 s, 792 kB/s
	1024KB: 67.4632 s, 777 kB/s
	2048KB: 69.9759 s, 749 kB/s

An unnamed SD card (Yakui):

         4k     195.873 s,  5.5 MB/s
         8k     123.425 s,  8.7 MB/s
         16k    86.6425 s, 12.4 MB/s
         32k    66.7519 s, 16.1 MB/s
==>      64k    58.5262 s, 18.3 MB/s
         128k   59.3847 s, 18.1 MB/s
         256k   59.3188 s, 18.1 MB/s
         512k   59.0218 s, 18.2 MB/s
---
 block/genhd.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
block/genhd.c +20 -0
@@ -623,6 +623,26 @@ void add_disk(struct gendisk *disk)
 	WARN_ON(retval);
 
 	disk_add_events(disk);
+
+	/*
+	 * Limit default readahead size for small devices.
+	 *        disk size    readahead size
+	 *               1M                8k
+	 *               4M               16k
+	 *              16M               32k
+	 *              64M               64k
+	 *             256M              128k
+	 *               1G              256k
+	 *               4G              512k
+	 *              16G             1024k
+	 *              64G             2048k
+	 *             256G             4096k
+	 */
+	if (get_capacity(disk)) {
+		unsigned long size = get_capacity(disk) >> 9;
+		size = 1UL << (ilog2(size) / 2);
+		bdi->ra_pages = min(bdi->ra_pages, size);
+	}
 }
 EXPORT_SYMBOL(add_disk);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#2 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

Quoted 6 lines · Wu Fengguang

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

Given that you mentioned the rotational flag and device size in this mail, as well as benchmarking with an intel SSD - did you measure how useful large read ahead sizes still are with highend Flash device that have extremly high read IOP rates?

#3 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

Quoted 4 lines · Christoph Hellwig
Quoted 3 lines · Wu Fengguang

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Quoted 8 lines
Quoted 3 lines

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

Given that you mentioned the rotational flag and device size in this mail, as well as benchmarking with an intel SSD - did you measure how useful large read ahead sizes still are with highend Flash device that have extremly high read IOP rates?

I don't know -- I don't have access to such highend devices.

However the patch changelog has the simple test script. It would be high appreciated if someone can help collect the data :)

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#4 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

In reply to Christoph Hellwig
Quoted 9 lines · Christoph Hellwig
Quoted 3 lines · Wu Fengguang

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

Given that you mentioned the rotational flag and device size in this mail, as well as benchmarking with an intel SSD - did you measure how useful large read ahead sizes still are with highend Flash device that have extremly high read IOP rates?

The more the IOPs the larger the "window" you need to keep everything going I suspect.

-Andi

Signature · 8 lines
[email protected] -- Speaking for myself only.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#5 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

In reply to Wu Fengguang
Quoted 36 lines · Wu Fengguang

Linus reports a _really_ small & slow (505kB, 15kB/s) USB device, on which blkid runs unpleasantly slow. He manages to optimize the blkid reads down to 1kB+16kB, but still kernel read-ahead turns it into 48kB.

lseek 0, read 1024 => readahead 4 pages (start of file)
lseek 1536, read 16384 => readahead 8 pages (page contiguous)

The readahead heuristics involved here are reasonable ones in general. So it's good to fix blkid with fadvise(RANDOM), as Linus already did.

For the kernel part, Linus suggests:
So maybe we could be less aggressive about read-ahead when the size of the device is small? Turning a 16kB read into a 64kB one is a big deal, when it's about 15% of the whole device!

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

        disk size    readahead size
     (scale by 4)      (scale by 2)
               1M                8k
               4M               16k
              16M               32k
              64M               64k
             256M              128k
        --------------------------- (*)
               1G              256k
               4G              512k
              16G             1024k
              64G             2048k
             256G             4096k
Quoted 2 lines

(*) Since the default readahead size is 128k, this limit only takes effect for devices whose size is less than 256M.

Scaling readahead by the size of the device may make sense up to a point. But really, that shouldn't be the only factor considered. Just because you have a big disk, it doesn't mean it's fast, and it sure doesn't mean that you should waste memory with readahead data that may not be used before it's evicted (whether due to readahead on data that isn't needed or thrashing of the page cache).

So, I think reducing the readahead size for smaller devices is fine. I'm not a big fan of going the other way.

Cheers,
Jeff

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#6 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

In reply to Wu Fengguang
Quoted 5 lines · On Mon, 21 Nov 2011 17:18:20 +0800 Wu Fengguang <[email protected]> wrote:

Linus reports a _really_ small & slow (505kB, 15kB/s) USB device, on which blkid runs unpleasantly slow. He manages to optimize the blkid reads down to 1kB+16kB, but still kernel read-ahead turns it into 48kB.

lseek 0, read 1024 => readahead 4 pages (start of file)

I'm disturbed that the code did a 4 page (16kbyte?) readahead after an lseek. Given the high probability that the next read will occur after a second lseek, that's a mistake.

Was an lseek to offset 0 special-cased?

Quoted 5 lines

lseek 1536, read 16384 => readahead 8 pages (page contiguous)

The readahead heuristics involved here are reasonable ones in general. So it's good to fix blkid with fadvise(RANDOM), as Linus already did.

Quoted 7 lines

For the kernel part, Linus suggests:
So maybe we could be less aggressive about read-ahead when the size of the device is small? Turning a 16kB read into a 64kB one is a big deal, when it's about 15% of the whole device!

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Spose so. Obviously there are other characteristics which should be considered when choosing a readaahead size, but one of them can be disk size and that's what this change does.

In a better world, userspace would run a work-out-what-readahead-size-to-use script each time a distro is installed and when new storage devices are added/detected. Userspace would then remember that readahead size for subsequent bootups.

In the real world, we shovel guaranteed-to-be-wrong guesswork into the kernel and everyone just uses the results. Sigh.

Quoted 13 lines
block/genhd.c +7 -0
@@ -623,6 +623,26 @@ void add_disk(struct gendisk *disk)
 	WARN_ON(retval);
 
 	disk_add_events(disk);
+
+	/*
+	 * Limit default readahead size for small devices.
+	 *        disk size    readahead size
+	 *               1M                8k
+	 *               4M               16k
+	 *              16M               32k

block/genhd.c void add_disk(struct gendisk *disk) · line 642

Quoted 10 lines
block/genhd.c +10 -0
+	 *              64M               64k
+	 *             256M              128k
+	 *               1G              256k
+	 *               4G              512k
+	 *              16G             1024k
+	 *              64G             2048k
+	 *             256G             4096k
+	 */
+	if (get_capacity(disk)) {
+		unsigned long size = get_capacity(disk) >> 9;

get_capacity() returns sector_t. This expression will overflow with a 2T disk. I'm not sure if we successfully support 2T disks on 32-bit machines, but changes like this will guarantee that we don't :)

block/genhd.c void add_disk(struct gendisk *disk) · line 643

Quoted 1 line
block/genhd.c +1 -0
+		size = 1UL << (ilog2(size) / 2);

I think there's a rounddown_pow_of_two() hiding in that expression?

block/genhd.c void add_disk(struct gendisk *disk) · line 644

Quoted 1 line
block/genhd.c +1 -0
+		bdi->ra_pages = min(bdi->ra_pages, size);

I don't have a clue why that min() is in there. It needs a comment, please.

block/genhd.c void add_disk(struct gendisk *disk) · line 645

Quoted 1 line
block/genhd.c +1 -0
+	}

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#7 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

Quoted 4 lines · Andrew Morton

In a better world, userspace would run a work-out-what-readahead-size-to-use script each time a distro is installed and when new storage devices are added/detected. Userspace would then remember that readahead size for subsequent bootups.

I'd be interested to hear what factors you think should be taken into account by such a script. I agree that there are certain things, like timing of reads of different sizes, or heuristics based on the size of installed memory, which could contribute to the default readahead size. However, other things, like memory pressure while running the desired workload, can't really be measured by an installer or one-time script.

Quoted 2 lines

In the real world, we shovel guaranteed-to-be-wrong guesswork into the kernel and everyone just uses the results. Sigh.

I'm not sure a userspace tool is the panacea you paint. However, if you can provide some guidance on what you think could make things better, I'm happy to give it a go.

Cheers,
Jeff

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author Acked-by Jens Axboe Acked-by Rik van Riel Tested-by Vivek Goyal Tested-by Linus Torvalds
#8 lore raw

Re: [PATCH 1/8] block: limit default readahead size for small devices

In reply to Andrew Morton
Quoted 7 lines · Andrew Morton
Quoted 4 lines · On Mon, 21 Nov 2011 17:18:20 +0800 Wu Fengguang <[email protected]> wrote:

Linus reports a _really_ small & slow (505kB, 15kB/s) USB device, on which blkid runs unpleasantly slow. He manages to optimize the blkid reads down to 1kB+16kB, but still kernel read-ahead turns it into 48kB.

Quoted 5 lines
Quoted 1 line

lseek 0, read 1024 => readahead 4 pages (start of file)

I'm disturbed that the code did a 4 page (16kbyte?) readahead after an lseek. Given the high probability that the next read will occur after a second lseek, that's a mistake.

Agreed.

Quoted 1 line

Was an lseek to offset 0 special-cased?

Yup, as you see in the last patch :)

Quoted 10 lines
Quoted 10 lines

lseek 1536, read 16384 => readahead 8 pages (page contiguous)

The readahead heuristics involved here are reasonable ones in general. So it's good to fix blkid with fadvise(RANDOM), as Linus already did.

For the kernel part, Linus suggests:
So maybe we could be less aggressive about read-ahead when the size of the device is small? Turning a 16kB read into a 64kB one is a big deal, when it's about 15% of the whole device!

Quoted 6 lines
Quoted 2 lines

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Spose so. Obviously there are other characteristics which should be considered when choosing a readaahead size, but one of them can be disk size and that's what this change does.

The other characteristics includes memory size, disk throughput, latency and (unfortunately) above all the real workload and its sensitivity to IO latencies.

The disk throughput and latency would be better than disk size, however the former is not that easy to measure. Disk size is readily available w/o any cost, hence this patch.

Quoted 7 lines

In a better world, userspace would run a work-out-what-readahead-size-to-use script each time a distro is installed and when new storage devices are added/detected. Userspace would then remember that readahead size for subsequent bootups.

In the real world, we shovel guaranteed-to-be-wrong guesswork into the kernel and everyone just uses the results. Sigh.

Heh. Disk characters should be measurable with some efforts. However I won't even try to guess the workload and user demands...

Practically, I would choose a meaningful default size (512KB or 1MB) for the majority and reduce it on small memory/slow disk systems (this patch does the easy work based on disk size).

Quoted 19 lines
Quoted 19 lines
block/genhd.c +13 -0
@@ -623,6 +623,26 @@ void add_disk(struct gendisk *disk)
 	WARN_ON(retval);
 
 	disk_add_events(disk);
+
+	/*
+	 * Limit default readahead size for small devices.
+	 *        disk size    readahead size
+	 *               1M                8k
+	 *               4M               16k
+	 *              16M               32k
+	 *              64M               64k
+	 *             256M              128k
+	 *               1G              256k
+	 *               4G              512k
+	 *              16G             1024k
+	 *              64G             2048k
Quoted 8 lines

block/genhd.c void add_disk(struct gendisk *disk) · line 642

Quoted 4 lines
block/genhd.c +4 -0
+	 *             256G             4096k
+	 */
+	if (get_capacity(disk)) {
+		unsigned long size = get_capacity(disk) >> 9;

get_capacity() returns sector_t. This expression will overflow with a 2T disk. I'm not sure if we successfully support 2T disks on 32-bit machines, but changes like this will guarantee that we don't :)

Good catch! I'll change the type to size_t.

Quoted 3 lines

block/genhd.c void add_disk(struct gendisk *disk) · line 643

Quoted 1 line
block/genhd.c +1 -0
+		size = 1UL << (ilog2(size) / 2);

I think there's a rounddown_pow_of_two() hiding in that expression?

Yeah, added a line of comment for that.

Quoted 4 lines

block/genhd.c void add_disk(struct gendisk *disk) · line 644

Quoted 1 line
block/genhd.c +1 -0
+		bdi->ra_pages = min(bdi->ra_pages, size);

I don't have a clue why that min() is in there. It needs a comment, please.

It's actually explained in the comment by word "Limit", I'll change it to "Scale down" to make it more obvious.

Thanks,
Fengguang
---
Subject: block: limit default readahead size for small devices
Date: Fri Nov 18 11:27:12 CST 2011

Linus reports a _really_ small & slow (505kB, 15kB/s) USB device, on which blkid runs unpleasantly slow. He manages to optimize the blkid reads down to 1kB+16kB, but still kernel read-ahead turns it into 48kB.

lseek 0, read 1024 => readahead 4 pages (start of file)
lseek 1536, read 16384 => readahead 8 pages (page contiguous)

The readahead heuristics involved here are reasonable ones in general. So it's good to fix blkid with fadvise(RANDOM), as Linus already did.

For the kernel part, Linus suggests:
So maybe we could be less aggressive about read-ahead when the size of the device is small? Turning a 16kB read into a 64kB one is a big deal, when it's about 15% of the whole device!

This looks reasonable: smaller device tend to be slower (USB sticks as well as micro/mobile/old hard disks).

Given that the non-rotational attribute is not always reported, we can take disk size as a max readahead size hint. This patch uses a formula that generates the following concrete limits:

        disk size    readahead size
     (scale by 4)      (scale by 2)
               1M                8k
               4M               16k
              16M               32k
              64M               64k
             256M              128k
        --------------------------- (*)
               1G              256k
               4G              512k
              16G             1024k
              64G             2048k
             256G             4096k

(*) Since the default readahead size is 128k, this limit only takes effect for devices whose size is less than 256M.

The formula is determined on the following data, collected by script:

	#!/bin/sh

	# please make sure BDEV is not mounted or opened by others
	BDEV=sdb

	for rasize in 4 16 32 64 128 256 512 1024 2048 4096 8192
	do
		echo $rasize > /sys/block/$BDEV/queue/read_ahead_kb
		time dd if=/dev/$BDEV of=/dev/null bs=4k count=102400
	done

The principle is, the formula shall not limit readahead size to such a degree that will impact some device's sequential read performance.

The Intel SSD is special in that its throughput increases steadily with larger readahead size. However it may take years for Linux to increase its default readahead size to 2MB, so we don't take it seriously in the formula.

SSD 80G Intel x25-M SSDSA2M080 (reported by Li Shaohua)

	rasize	1st run		2nd run
	----------------------------------
	  4k	123 MB/s	122 MB/s
	 16k  	153 MB/s	153 MB/s
	 32k	161 MB/s	162 MB/s
	 64k	167 MB/s	168 MB/s
	128k	197 MB/s	197 MB/s
	256k	217 MB/s	217 MB/s
	512k	238 MB/s	234 MB/s
	  1M	251 MB/s	248 MB/s
	  2M	259 MB/s	257 MB/s
==>	  4M	269 MB/s	264 MB/s
	  8M	266 MB/s	266 MB/s

Note that ==> points to the readahead size that yields plateau throughput.

SSD 22G MARVELL SD88SA02 MP1F (reported by Jens Axboe)

	rasize  1st             2nd
	--------------------------------
	  4k     41 MB/s         41 MB/s
	 16k     85 MB/s         81 MB/s
	 32k    102 MB/s        109 MB/s
	 64k    125 MB/s        144 MB/s
	128k    183 MB/s        185 MB/s
	256k    216 MB/s        216 MB/s
	512k    216 MB/s        236 MB/s
	1024k   251 MB/s        252 MB/s
	  2M    258 MB/s        258 MB/s
==>       4M    266 MB/s        266 MB/s
	  8M    266 MB/s        266 MB/s

SSD 30G SanDisk SATA 5000

	  4k	29.6 MB/s	29.6 MB/s	29.6 MB/s
	 16k	52.1 MB/s	52.1 MB/s	52.1 MB/s
	 32k	61.5 MB/s	61.5 MB/s	61.5 MB/s
	 64k	67.2 MB/s	67.2 MB/s	67.1 MB/s
	128k	71.4 MB/s	71.3 MB/s	71.4 MB/s
	256k	73.4 MB/s	73.4 MB/s	73.3 MB/s
==>	512k	74.6 MB/s	74.6 MB/s	74.6 MB/s
	  1M	74.7 MB/s	74.6 MB/s	74.7 MB/s
	  2M	76.1 MB/s	74.6 MB/s	74.6 MB/s

USB stick 32G Teclast CoolFlash idVendor=1307, idProduct=0165

	  4k	7.9 MB/s 	7.9 MB/s 	7.9 MB/s
	 16k	17.9 MB/s	17.9 MB/s	17.9 MB/s
	 32k	24.5 MB/s	24.5 MB/s	24.5 MB/s
	 64k	28.7 MB/s	28.7 MB/s	28.7 MB/s
	128k	28.8 MB/s	28.9 MB/s	28.9 MB/s
==>	256k	30.5 MB/s	30.5 MB/s	30.5 MB/s
	512k	30.9 MB/s	31.0 MB/s	30.9 MB/s
	  1M	31.0 MB/s	30.9 MB/s	30.9 MB/s
	  2M	30.9 MB/s	30.9 MB/s	30.9 MB/s

USB stick 4G SanDisk Cruzer idVendor=0781, idProduct=5151

	  4k	6.4 MB/s 	6.4 MB/s 	6.4 MB/s
	 16k	13.4 MB/s	13.4 MB/s	13.2 MB/s
	 32k	17.8 MB/s	17.9 MB/s	17.8 MB/s
	 64k	21.3 MB/s	21.3 MB/s	21.2 MB/s
	128k	21.4 MB/s	21.4 MB/s	21.4 MB/s
==>	256k	23.3 MB/s	23.2 MB/s	23.2 MB/s
	512k	23.3 MB/s	23.8 MB/s	23.4 MB/s
	  1M	23.8 MB/s	23.4 MB/s	23.3 MB/s
	  2M	23.4 MB/s	23.2 MB/s	23.4 MB/s

USB stick 2G idVendor=0204, idProduct=6025 SerialNumber: 08082005000113

	  4k	6.7 MB/s 	6.9 MB/s 	6.7 MB/s
	 16k	11.7 MB/s	11.7 MB/s	11.7 MB/s
	 32k	12.4 MB/s	12.4 MB/s	12.4 MB/s
   	 64k	13.4 MB/s	13.4 MB/s	13.4 MB/s
	128k	13.4 MB/s	13.4 MB/s	13.4 MB/s
==>	256k	13.6 MB/s	13.6 MB/s	13.6 MB/s
	512k	13.7 MB/s	13.7 MB/s	13.7 MB/s
	  1M	13.7 MB/s	13.7 MB/s	13.7 MB/s
	  2M	13.7 MB/s	13.7 MB/s	13.7 MB/s

64 MB, USB full speed (collected by Clemens Ladisch)
Bus 003 Device 003: ID 08ec:0011 M-Systems Flash Disk Pioneers DiskOnKey

	4KB:    139.339 s, 376 kB/s
	16KB:   81.0427 s, 647 kB/s
	32KB:   71.8513 s, 730 kB/s
==>	64KB:   67.3872 s, 778 kB/s
	128KB:  67.5434 s, 776 kB/s
	256KB:  65.9019 s, 796 kB/s
	512KB:  66.2282 s, 792 kB/s
	1024KB: 67.4632 s, 777 kB/s
	2048KB: 69.9759 s, 749 kB/s

An unnamed SD card (Yakui):

         4k     195.873 s,  5.5 MB/s
         8k     123.425 s,  8.7 MB/s
         16k    86.6425 s, 12.4 MB/s
         32k    66.7519 s, 16.1 MB/s
==>      64k    58.5262 s, 18.3 MB/s
         128k   59.3847 s, 18.1 MB/s
         256k   59.3188 s, 18.1 MB/s
         512k   59.0218 s, 18.2 MB/s
---
 block/genhd.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
block/genhd.c +20 -0
@@ -578,6 +578,7 @@ exit:
 void add_disk(struct gendisk *disk)
 {
 	struct backing_dev_info *bdi;
+	size_t size;
 	dev_t devt;
 	int retval;
 
@@ -623,6 +624,25 @@ void add_disk(struct gendisk *disk)
 	WARN_ON(retval);
 
 	disk_add_events(disk);
+
+	/*
+	 * Scale down default readahead size for small devices.
+	 *        disk size    readahead size
+	 *               1M                8k
+	 *               4M               16k
+	 *              16M               32k
+	 *              64M               64k
+	 *             255M               64k (the round down effect)
+	 *             256M              128k
+	 *               1G              256k
+	 *               4G              512k
+	 *              16G             1024k
+	 */
+	size = get_capacity(disk);
+	if (size) {
+		size = 1 << (ilog2(size >> 9) / 2);
+		bdi->ra_pages = min(bdi->ra_pages, size);
+	}
 }
 EXPORT_SYMBOL(add_disk);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

PATCH 2/8 readahead: make default readahead size a kernel parameter

In reply to Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

---
 Documentation/kernel-parameters.txt |    6 ++++++
 block/blk-core.c                    |    3 +--
 fs/fuse/inode.c                     |    2 +-
 mm/readahead.c                      |   19 +++++++++++++++++++
 4 files changed, 27 insertions(+), 3 deletions(-)
Documentation/kernel-parameters.txt +6 -0
@@ -2245,6 +2245,12 @@ bytes respectively. Such letter suffixes
 			Run specified binary instead of /init from the ramdisk,
 			used for early userspace startup. See initrd.
 
+	readahead=nn[KM]
+			Default max readahead size for block devices.
+
+			This default max readahead size may be overrode
+			in some cases, notably NFS, btrfs and software RAID.
+
 	reboot=		[BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
 			Format: <reboot_mode>[,<reboot_mode2>[,...]]
 			See arch/*/kernel/reboot.c or arch/*/kernel/process.c
block/blk-core.c +1 -2
@@ -462,8 +462,7 @@ struct request_queue *blk_alloc_queue_no
 	if (!q)
 		return NULL;
 
-	q->backing_dev_info.ra_pages =
-			(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+	q->backing_dev_info.ra_pages = default_backing_dev_info.ra_pages;
 	q->backing_dev_info.state = 0;
 	q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
 	q->backing_dev_info.name = "block";
fs/fuse/inode.c +1 -1
@@ -878,7 +878,7 @@ static int fuse_bdi_init(struct fuse_con
 	int err;
 
 	fc->bdi.name = "fuse";
-	fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+	fc->bdi.ra_pages = default_backing_dev_info.ra_pages;
 	/* fuse does it's own writeback accounting */
 	fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
 
mm/readahead.c +19 -0
@@ -18,6 +18,25 @@
 #include <linux/pagevec.h>
 #include <linux/pagemap.h>
 
+static int __init config_readahead_size(char *str)
+{
+	unsigned long bytes;
+
+	if (!str)
+		return -EINVAL;
+	bytes = memparse(str, &str);
+	if (*str != '\0')
+		return -EINVAL;
+
+	/* missed 'k'/'m' suffixes? */
+	if (bytes && bytes < PAGE_CACHE_SIZE)
+		return -EINVAL;
+
+	default_backing_dev_info.ra_pages = bytes / PAGE_CACHE_SIZE;
+	return 0;
+}
+early_param("readahead", config_readahead_size);
+
 /*
  * Initialise a struct file's readahead state.  Assumes that the caller has
  * memset *ra to zero.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#10 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 4 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

Is a boot-time paramter really such a good idea? I would at least make it a sysctl so that it's run-time controllable, including beeing able to set it from initscripts.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 7 lines · Christoph Hellwig
Quoted 4 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

Is a boot-time paramter really such a good idea? I would at least

It's most convenient to set at boot time, because the default size will be used to initialize all the block devices.

Quoted 2 lines

make it a sysctl so that it's run-time controllable, including beeing able to set it from initscripts.

Once boot up, it's more natural to set the size one by one, for example

        blockdev --setra 1024 /dev/sda2

or
echo 512 > /sys/block/sda/queue/read_ahead_kb

And you still have the chance to modify the global default, but the change will only be inherited by newly created devices thereafter:

echo 512 > /sys/devices/virtual/bdi/default/read_ahead_kb

The above command is very suitable for use in initscripts. However there are no natural way to do sysctl as there is no such a global value.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#12 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 22 lines · Wu Fengguang
Quoted 7 lines · Christoph Hellwig
Quoted 4 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

Is a boot-time paramter really such a good idea? I would at least

It's most convenient to set at boot time, because the default size will be used to initialize all the block devices.

Quoted 2 lines

make it a sysctl so that it's run-time controllable, including beeing able to set it from initscripts.

Once boot up, it's more natural to set the size one by one, for example

        blockdev --setra 1024 /dev/sda2

or
echo 512 > /sys/block/sda/queue/read_ahead_kb

Quoted 8 lines

And you still have the chance to modify the global default, but the change will only be inherited by newly created devices thereafter:

echo 512 > /sys/devices/virtual/bdi/default/read_ahead_kb

The above command is very suitable for use in initscripts. However there are no natural way to do sysctl as there is no such a global value.

Well, you can always have an udev rule to set read_ahead_kb to whatever
you want. In some respect that looks like a nicer solution to me...

Honza

Signature · 9 lines
Jan Kara <[email protected]>
SUSE Labs, CR

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#13 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 26 lines · Jan Kara
Quoted 25 lines · Wu Fengguang
Quoted 7 lines · Christoph Hellwig
Quoted 4 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

Is a boot-time paramter really such a good idea? I would at least

It's most convenient to set at boot time, because the default size will be used to initialize all the block devices.

Quoted 2 lines

make it a sysctl so that it's run-time controllable, including beeing able to set it from initscripts.

Once boot up, it's more natural to set the size one by one, for example

        blockdev --setra 1024 /dev/sda2

or
echo 512 > /sys/block/sda/queue/read_ahead_kb

And you still have the chance to modify the global default, but the change will only be inherited by newly created devices thereafter:

Quoted 7 lines
Quoted 5 lines

echo 512 > /sys/devices/virtual/bdi/default/read_ahead_kb

The above command is very suitable for use in initscripts. However there are no natural way to do sysctl as there is no such a global value.

Well, you can always have an udev rule to set read_ahead_kb to whatever
you want. In some respect that looks like a nicer solution to me...

And one that has already been in use for exactly this purpose for years. Indeed, it's far more flexible because you can give different types of devices different default readahead settings quite easily, and it you can set different defaults for just about any tunable parameter (e.g. readahead, ctq depth, max IO sizes, etc) in the same way.

Hence I don't think we should treat default readahead any differently from any other configurable storage parameter - we've already got places to change the per-device defaults to something sensible at boot/discovery time....

Cheers,

Dave.

Signature · 9 lines
Dave Chinner
[email protected]

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#14 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 35 lines · Dave Chinner
Quoted 26 lines · Jan Kara
Quoted 25 lines · Wu Fengguang
Quoted 7 lines · Christoph Hellwig
Quoted 4 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

Is a boot-time paramter really such a good idea? I would at least

It's most convenient to set at boot time, because the default size will be used to initialize all the block devices.

Quoted 2 lines

make it a sysctl so that it's run-time controllable, including beeing able to set it from initscripts.

Once boot up, it's more natural to set the size one by one, for example

        blockdev --setra 1024 /dev/sda2

or
echo 512 > /sys/block/sda/queue/read_ahead_kb

And you still have the chance to modify the global default, but the change will only be inherited by newly created devices thereafter:

Quoted 7 lines
Quoted 5 lines

echo 512 > /sys/devices/virtual/bdi/default/read_ahead_kb

The above command is very suitable for use in initscripts. However there are no natural way to do sysctl as there is no such a global value.

Well, you can always have an udev rule to set read_ahead_kb to whatever
you want. In some respect that looks like a nicer solution to me...

Quoted 6 lines

And one that has already been in use for exactly this purpose for years. Indeed, it's far more flexible because you can give different types of devices different default readahead settings quite easily, and it you can set different defaults for just about any tunable parameter (e.g. readahead, ctq depth, max IO sizes, etc) in the same way.

I'm interested in this usage, too. Would you share some of your rules?

Quoted 4 lines

Hence I don't think we should treat default readahead any differently from any other configurable storage parameter - we've already got places to change the per-device defaults to something sensible at boot/discovery time....

OK, I'll drop this patch.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#15 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 7 lines · Wu Fengguang
Quoted 6 lines · Dave Chinner
Quoted 5 lines · Jan Kara
Quoted 4 lines · Wu Fengguang
Quoted 3 lines · Christoph Hellwig
Quoted 2 lines · Wu Fengguang

From: Nikanth Karthikesan<[email protected]>

[...]

Quoted 10 lines
Quoted 7 lines

And one that has already been in use for exactly this purpose for years. Indeed, it's far more flexible because you can give different types of devices different default readahead settings quite easily, and it you can set different defaults for just about any tunable parameter (e.g. readahead, ctq depth, max IO sizes, etc) in the same way.

I'm interested in this usage, too. Would you share some of your rules?

FYI - This is an example of a rules Suse delivers in SLES @ s390 for a while now. With little modifications it could be used for all Dave mentioned above.

cat /etc/udev/rules.d/60-readahead.rules
#

# Rules to set an increased default max readahead size for s390 disk devices

# This file should be installed in /etc/udev/rules.d

#

SUBSYSTEM!="block", GOTO="ra_end"

ACTION!="add", GOTO="ra_end"

# on device add set initial readahead to 512 (instead of in kernel 128) 

KERNEL=="sd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

KERNEL=="dasd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

LABEL="ra_end"

Signature · 9 lines
Grüsse / regards, Christian Ehrhardt
IBM Linux Technology Center, System z Linux Performance

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#16 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 20 lines · Christian Ehrhardt
Quoted 7 lines · Wu Fengguang
Quoted 6 lines · Dave Chinner
Quoted 5 lines · Jan Kara
Quoted 4 lines · Wu Fengguang
Quoted 3 lines · Christoph Hellwig
Quoted 2 lines · Wu Fengguang

From: Nikanth Karthikesan<[email protected]>

[...]

Quoted 8 lines
Quoted 7 lines

And one that has already been in use for exactly this purpose for years. Indeed, it's far more flexible because you can give different types of devices different default readahead settings quite easily, and it you can set different defaults for just about any tunable parameter (e.g. readahead, ctq depth, max IO sizes, etc) in the same way.

Quoted 6 lines
Quoted 2 lines

I'm interested in this usage, too. Would you share some of your rules?

FYI - This is an example of a rules Suse delivers in SLES @ s390 for a while now. With little modifications it could be used for all Dave mentioned above.

It's a really good example, thank you!

Quoted 17 lines

cat /etc/udev/rules.d/60-readahead.rules
#

# Rules to set an increased default max readahead size for s390 disk devices

# This file should be installed in /etc/udev/rules.d

#

SUBSYSTEM!="block", GOTO="ra_end"

Quoted 7 lines

ACTION!="add", GOTO="ra_end"

# on device add set initial readahead to 512 (instead of in kernel 128) 

KERNEL=="sd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

KERNEL=="dasd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

So SLES (@s390 and maybe more) is already shipping with 512kb readahead size? Good to know this!

Thanks,
Fengguang

Quoted 9 lines

LABEL="ra_end"

Signature · 2 lines
Grüsse / regards, Christian Ehrhardt
IBM Linux Technology Center, System z Linux Performance

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#17 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 19 lines · Wu Fengguang
Quoted 19 lines

cat /etc/udev/rules.d/60-readahead.rules
#

# Rules to set an increased default max readahead size for s390 disk devices

# This file should be installed in /etc/udev/rules.d

#

SUBSYSTEM!="block", GOTO="ra_end"

ACTION!="add", GOTO="ra_end"

Quoted 8 lines
Quoted 5 lines
# on device add set initial readahead to 512 (instead of in kernel 128) 

KERNEL=="sd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

KERNEL=="dasd*[!0-9]", ATTR{queue/read_ahead_kb}="512"

So SLES (@s390 and maybe more) is already shipping with 512kb readahead size? Good to know this!

SLES (and openSUSE) since about 2.6.16 times is shipping with 512kb
readahead on everything... With some types of storage it makes a significant difference.

Honza

Signature · 9 lines
Jan Kara <[email protected]>
SUSE Labs, CR

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#18 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

In reply to Wu Fengguang
Quoted 21 lines · Wu Fengguang

From: Nikanth Karthikesan <[email protected]>

Add new kernel parameter "readahead=", which allows user to override the static VM_MAX_READAHEAD=128kb.

---
 Documentation/kernel-parameters.txt |    6 ++++++
 block/blk-core.c                    |    3 +--
 fs/fuse/inode.c                     |    2 +-
 mm/readahead.c                      |   19 +++++++++++++++++++
 4 files changed, 27 insertions(+), 3 deletions(-)

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes · line 2251

Quoted 7 lines
Documentation/kernel-parameters.txt +4 -0
@@ -2245,6 +2245,12 @@ bytes respectively. Such letter suffixes
 			Run specified binary instead of /init from the ramdisk,
 			used for early userspace startup. See initrd.
 
+	readahead=nn[KM]
+			Default max readahead size for block devices.
+
+			This default max readahead size may be overrode

s/overrode/overridden/ ?

Thanks.

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes · line 2256

Quoted 5 lines
Documentation/kernel-parameters.txt +2 -0
+			in some cases, notably NFS, btrfs and software RAID.
+
 	reboot=		[BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
 			Format: <reboot_mode>[,<reboot_mode2>[,...]]
 			See arch/*/kernel/reboot.c or arch/*/kernel/process.c

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#19 lore raw

Re: [PATCH 2/8] readahead: make default readahead size a kernel parameter

Quoted 6 lines

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes · line 2251

Quoted 4 lines
Documentation/kernel-parameters.txt +4 -0
+	readahead=nn[KM]
+			Default max readahead size for block devices.
+
+			This default max readahead size may be overrode

s/overrode/overridden/ ?

Ah sure. Good catch!

Thanks,
Fengguang

#20 lore raw

PATCH 3/8 readahead: replace ra->mmap_miss with ra->ra_flags

In reply to Wu Fengguang

Introduce a readahead flags field and embed the existing mmap_miss in it (mainly to save space).

It will be possible to lose the flags in race conditions, however the impact should be limited. For the race to happen, there must be two threads sharing the same file descriptor to be in page fault or readahead at the same time.

Note that it has always been racy for "page faults" at the same time.

And if ever the race happen, we'll lose one mmap_miss++ or mmap_miss--. Which may change some concrete readahead behavior, but won't really impact overall I/O performance.

---
 include/linux/fs.h |   31 ++++++++++++++++++++++++++++++-
 mm/filemap.c       |    9 ++-------
 2 files changed, 32 insertions(+), 8 deletions(-)
include/linux/fs.h +30 -1
@@ -945,10 +945,39 @@ struct file_ra_state {
 					   there are only # of pages ahead */
 
 	unsigned int ra_pages;		/* Maximum readahead window */
-	unsigned int mmap_miss;		/* Cache miss stat for mmap accesses */
+	unsigned int ra_flags;
 	loff_t prev_pos;		/* Cache last read() position */
 };
 
+/* ra_flags bits */
+#define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+
+/*
+ * Don't do ra_flags++ directly to avoid possible overflow:
+ * the ra fields can be accessed concurrently in a racy way.
+ */
+static inline unsigned int ra_mmap_miss_inc(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	/* the upper bound avoids banging the cache line unnecessarily */
+	if (miss < READAHEAD_MMAP_MISS) {
+		miss++;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+	return miss;
+}
+
+static inline void ra_mmap_miss_dec(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	if (miss) {
+		miss--;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+}
+
 /*
  * Check if @index falls in the readahead windows.
  */
mm/filemap.c +2 -7
@@ -1597,15 +1597,11 @@ static void do_sync_mmap_readahead(struc
 		return;
 	}
 
-	/* Avoid banging the cache line if not needed */
-	if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
-		ra->mmap_miss++;
-
 	/*
 	 * Do we miss much more than hit in this file? If so,
 	 * stop bothering with read-ahead. It will only hurt.
 	 */
-	if (ra->mmap_miss > MMAP_LOTSAMISS)
+	if (ra_mmap_miss_inc(ra) > MMAP_LOTSAMISS)
 		return;
 
 	/*
@@ -1633,8 +1629,7 @@ static void do_async_mmap_readahead(stru
 	/* If we don't want any read-ahead, don't bother */
 	if (VM_RandomReadHint(vma))
 		return;
-	if (ra->mmap_miss > 0)
-		ra->mmap_miss--;
+	ra_mmap_miss_dec(ra);
 	if (PageReadahead(page))
 		page_cache_async_readahead(mapping, ra, file,
 					   page, offset, ra->ra_pages);

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

Acked-by on v1 3/8
#21 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

Hi,

I'm not quite sure why you copied me in to this patch, but I've had a look at it and it seems ok to me. Some of the other patches in this series look as if they might be rather useful for the GFS2 dir readahead code though, so I'll be keeping an eye on developments in this area,

Steve.

Quoted 89 lines · Wu Fengguang

plain text document attachment (readahead-flags.patch) Introduce a readahead flags field and embed the existing mmap_miss in it (mainly to save space).

It will be possible to lose the flags in race conditions, however the impact should be limited. For the race to happen, there must be two threads sharing the same file descriptor to be in page fault or readahead at the same time.

Note that it has always been racy for "page faults" at the same time.

And if ever the race happen, we'll lose one mmap_miss++ or mmap_miss--. Which may change some concrete readahead behavior, but won't really impact overall I/O performance.

---
 include/linux/fs.h |   31 ++++++++++++++++++++++++++++++-
 mm/filemap.c       |    9 ++-------
 2 files changed, 32 insertions(+), 8 deletions(-)
include/linux/fs.h +30 -1
@@ -945,10 +945,39 @@ struct file_ra_state {
 					   there are only # of pages ahead */
 
 	unsigned int ra_pages;		/* Maximum readahead window */
-	unsigned int mmap_miss;		/* Cache miss stat for mmap accesses */
+	unsigned int ra_flags;
 	loff_t prev_pos;		/* Cache last read() position */
 };
 
+/* ra_flags bits */
+#define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+
+/*
+ * Don't do ra_flags++ directly to avoid possible overflow:
+ * the ra fields can be accessed concurrently in a racy way.
+ */
+static inline unsigned int ra_mmap_miss_inc(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	/* the upper bound avoids banging the cache line unnecessarily */
+	if (miss < READAHEAD_MMAP_MISS) {
+		miss++;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+	return miss;
+}
+
+static inline void ra_mmap_miss_dec(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	if (miss) {
+		miss--;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+}
+
 /*
  * Check if @index falls in the readahead windows.
  */
mm/filemap.c +1 -5
@@ -1597,15 +1597,11 @@ static void do_sync_mmap_readahead(struc
 		return;
 	}
 
-	/* Avoid banging the cache line if not needed */
-	if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
-		ra->mmap_miss++;
-
 	/*
 	 * Do we miss much more than hit in this file? If so,
 	 * stop bothering with read-ahead. It will only hurt.
 	 */
-	if (ra->mmap_miss > MMAP_LOTSAMISS)
+	if (ra_mmap_miss_inc(ra) > MMAP_LOTSAMISS)
 		return;
 
 	/*

mm/filemap.c static void do_async_mmap_readahead(stru · line 1635

Quoted 9 lines
mm/filemap.c +1 -2
@@ -1633,8 +1629,7 @@ static void do_async_mmap_readahead(stru
 	/* If we don't want any read-ahead, don't bother */
 	if (VM_RandomReadHint(vma))
 		return;
-	if (ra->mmap_miss > 0)
-		ra->mmap_miss--;
+	ra_mmap_miss_dec(ra);
 	if (PageReadahead(page))
 		page_cache_async_readahead(mapping, ra, file,
 					   page, offset, ra->ra_pages);

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#22 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

Hi Steven,

Quoted 3 lines · Steven Whitehouse

Hi,

I'm not quite sure why you copied me in to this patch, but I've had a

Yeah it's such an old patch that I've forgotten why I added CC to you ;)

Quoted 5 lines

look at it and it seems ok to me. Some of the other patches in this series look as if they might be rather useful for the GFS2 dir readahead code though, so I'll be keeping an eye on developments in this area,

Thanks! That reminds me of the "metadata readahead". It should be possible to do more metadata readahead in future, hence we might add a "meta_io" column in the readahead stats file :)

Thanks,
Fengguang

Quoted 86 lines · Wu Fengguang
Quoted 85 lines

plain text document attachment (readahead-flags.patch) Introduce a readahead flags field and embed the existing mmap_miss in it (mainly to save space).

It will be possible to lose the flags in race conditions, however the impact should be limited. For the race to happen, there must be two threads sharing the same file descriptor to be in page fault or readahead at the same time.

Note that it has always been racy for "page faults" at the same time.

And if ever the race happen, we'll lose one mmap_miss++ or mmap_miss--. Which may change some concrete readahead behavior, but won't really impact overall I/O performance.

---
 include/linux/fs.h |   31 ++++++++++++++++++++++++++++++-
 mm/filemap.c       |    9 ++-------
 2 files changed, 32 insertions(+), 8 deletions(-)
include/linux/fs.h +30 -1
@@ -945,10 +945,39 @@ struct file_ra_state {
 					   there are only # of pages ahead */
 
 	unsigned int ra_pages;		/* Maximum readahead window */
-	unsigned int mmap_miss;		/* Cache miss stat for mmap accesses */
+	unsigned int ra_flags;
 	loff_t prev_pos;		/* Cache last read() position */
 };
 
+/* ra_flags bits */
+#define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+
+/*
+ * Don't do ra_flags++ directly to avoid possible overflow:
+ * the ra fields can be accessed concurrently in a racy way.
+ */
+static inline unsigned int ra_mmap_miss_inc(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	/* the upper bound avoids banging the cache line unnecessarily */
+	if (miss < READAHEAD_MMAP_MISS) {
+		miss++;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+	return miss;
+}
+
+static inline void ra_mmap_miss_dec(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	if (miss) {
+		miss--;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+}
+
 /*
  * Check if @index falls in the readahead windows.
  */
mm/filemap.c +1 -5
@@ -1597,15 +1597,11 @@ static void do_sync_mmap_readahead(struc
 		return;
 	}
 
-	/* Avoid banging the cache line if not needed */
-	if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
-		ra->mmap_miss++;
-
 	/*
 	 * Do we miss much more than hit in this file? If so,
 	 * stop bothering with read-ahead. It will only hurt.
 	 */
-	if (ra->mmap_miss > MMAP_LOTSAMISS)
+	if (ra_mmap_miss_inc(ra) > MMAP_LOTSAMISS)
 		return;
 
Quoted 15 lines

mm/filemap.c static void do_async_mmap_readahead(stru · line 1635

Quoted 13 lines
mm/filemap.c +1 -2
 	/*
@@ -1633,8 +1629,7 @@ static void do_async_mmap_readahead(stru
 	/* If we don't want any read-ahead, don't bother */
 	if (VM_RandomReadHint(vma))
 		return;
-	if (ra->mmap_miss > 0)
-		ra->mmap_miss--;
+	ra_mmap_miss_dec(ra);
 	if (PageReadahead(page))
 		page_cache_async_readahead(mapping, ra, file,
 					   page, offset, ra->ra_pages);

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#23 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

In reply to Wu Fengguang
Quoted 2 lines · On Mon, 21 Nov 2011 17:18:22 +0800 Wu Fengguang <[email protected]> wrote:

Introduce a readahead flags field and embed the existing mmap_miss in it (mainly to save space).

What an ugly patch.

Quoted 23 lines

It will be possible to lose the flags in race conditions, however the impact should be limited. For the race to happen, there must be two threads sharing the same file descriptor to be in page fault or readahead at the same time.

Note that it has always been racy for "page faults" at the same time.

And if ever the race happen, we'll lose one mmap_miss++ or mmap_miss--. Which may change some concrete readahead behavior, but won't really impact overall I/O performance.

---
 include/linux/fs.h |   31 ++++++++++++++++++++++++++++++-
 mm/filemap.c       |    9 ++-------
 2 files changed, 32 insertions(+), 8 deletions(-)

include/linux/fs.h struct file_ra_state { · line 948

Quoted 5 lines
include/linux/fs.h +1 -1
@@ -945,10 +945,39 @@ struct file_ra_state {
 					   there are only # of pages ahead */
 
 	unsigned int ra_pages;		/* Maximum readahead window */
-	unsigned int mmap_miss;		/* Cache miss stat for mmap accesses */
+	unsigned int ra_flags;

And it doesn't actually save any space, unless ra_flags gets used for something else in a subsequent patch. And if it does, perhaps ra_flags should be ulong, which is compatible with the bitops.h code.

Or perhaps we should use a bitfield and let the compiler do the work.

Quoted 21 lines
include/linux/fs.h +18 -0
 	loff_t prev_pos;		/* Cache last read() position */
 };
 
+/* ra_flags bits */
+#define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+
+/*
+ * Don't do ra_flags++ directly to avoid possible overflow:
+ * the ra fields can be accessed concurrently in a racy way.
+ */
+static inline unsigned int ra_mmap_miss_inc(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	/* the upper bound avoids banging the cache line unnecessarily */
+	if (miss < READAHEAD_MMAP_MISS) {
+		miss++;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+	return miss;
+}

include/linux/fs.h struct file_ra_state { · line 979

Quoted 10 lines
include/linux/fs.h +10 -0
+
+static inline void ra_mmap_miss_dec(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	if (miss) {
+		miss--;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+}

It's strange that ra_mmap_miss_inc() returns the new value whereas ra_mmap_miss_dec() returns void.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#24 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

Quoted 7 lines · Andrew Morton
Quoted 2 lines · On Mon, 21 Nov 2011 17:18:22 +0800 Wu Fengguang <[email protected]> wrote:

Introduce a readahead flags field and embed the existing mmap_miss in it (mainly to save space).

What an ugly patch.

Indeed..

Quoted 25 lines
Quoted 25 lines

It will be possible to lose the flags in race conditions, however the impact should be limited. For the race to happen, there must be two threads sharing the same file descriptor to be in page fault or readahead at the same time.

Note that it has always been racy for "page faults" at the same time.

And if ever the race happen, we'll lose one mmap_miss++ or mmap_miss--. Which may change some concrete readahead behavior, but won't really impact overall I/O performance.

---
 include/linux/fs.h |   31 ++++++++++++++++++++++++++++++-
 mm/filemap.c       |    9 ++-------
 2 files changed, 32 insertions(+), 8 deletions(-)
include/linux/fs.h +0 -0
@@ -945,10 +945,39 @@ struct file_ra_state {
 					   there are only # of pages ahead */
 
Quoted 6 lines

include/linux/fs.h struct file_ra_state { · line 948

Quoted 3 lines
include/linux/fs.h +1 -1
 	unsigned int ra_pages;		/* Maximum readahead window */
-	unsigned int mmap_miss;		/* Cache miss stat for mmap accesses */
+	unsigned int ra_flags;

And it doesn't actually save any space, unless ra_flags gets used for something else in a subsequent patch. And if it does, perhaps ra_flags

Because it's a preparation patch. There will be more fields defined later.

Quoted 2 lines

should be ulong, which is compatible with the bitops.h code. Or perhaps we should use a bitfield and let the compiler do the work.

What if we do

        u16     mmap_miss;
        u16     ra_flags;

That would get rid of this patch. I'd still like to pack the various flags as well as pattern into one single ra_flags, which makes it convenient to pass things around (as one single parameter).

Quoted 26 lines
Quoted 26 lines
include/linux/fs.h +23 -0
 	loff_t prev_pos;		/* Cache last read() position */
 };
 
+/* ra_flags bits */
+#define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+
+/*
+ * Don't do ra_flags++ directly to avoid possible overflow:
+ * the ra fields can be accessed concurrently in a racy way.
+ */
+static inline unsigned int ra_mmap_miss_inc(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
+	/* the upper bound avoids banging the cache line unnecessarily */
+	if (miss < READAHEAD_MMAP_MISS) {
+		miss++;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+	return miss;
+}
+
+static inline void ra_mmap_miss_dec(struct file_ra_state *ra)
+{
+	unsigned int miss = ra->ra_flags & READAHEAD_MMAP_MISS;
+
Quoted 8 lines

include/linux/fs.h struct file_ra_state { · line 979

Quoted 5 lines
include/linux/fs.h +5 -0
+	if (miss) {
+		miss--;
+		ra->ra_flags = miss | (ra->ra_flags & ~READAHEAD_MMAP_MISS);
+	}
+}

It's strange that ra_mmap_miss_inc() returns the new value whereas ra_mmap_miss_dec() returns void.

Simply because no one need to check the return value of ra_mmap_miss_dec()... But yeah it's good to make them look symmetry.

Thanks,
Fengguang

maintainer
#25 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

Quoted 11 lines · On Wed, 23 Nov 2011 20:47:45 +0800 Wu Fengguang <[email protected]> wrote:
Quoted 2 lines

should be ulong, which is compatible with the bitops.h code. Or perhaps we should use a bitfield and let the compiler do the work.

What if we do

        u16     mmap_miss;
        u16     ra_flags;

That would get rid of this patch. I'd still like to pack the various flags as well as pattern into one single ra_flags, which makes it convenient to pass things around (as one single parameter).

I'm not sure that this will improve things much...

Again, how does the code look if you use a bitfield and let the compiler do the worK?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#26 lore raw

Re: [PATCH 3/8] readahead: replace ra->mmap_miss with ra->ra_flags

Quoted 11 lines · Andrew Morton
Quoted 8 lines · On Wed, 23 Nov 2011 20:47:45 +0800 Wu Fengguang <[email protected]> wrote:
Quoted 2 lines

should be ulong, which is compatible with the bitops.h code. Or perhaps we should use a bitfield and let the compiler do the work.

What if we do

        u16     mmap_miss;
        u16     ra_flags;
Quoted 8 lines
Quoted 3 lines

That would get rid of this patch. I'd still like to pack the various flags as well as pattern into one single ra_flags, which makes it convenient to pass things around (as one single parameter).

I'm not sure that this will improve things much...

Again, how does the code look if you use a bitfield and let the compiler do the worK?

It results in much clean code, as you may find in the V2 patches :-)

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#27 lore raw

PATCH 4/8 readahead: record readahead patterns

In reply to Wu Fengguang

Record the readahead pattern in ra_flags and extend the ra_submit() parameters, to be used by the next readahead tracing/stats patches.

7 patterns are defined:

pattern readahead for
-----------------------------------------------------------
RA_PATTERN_INITIAL start-of-file read
RA_PATTERN_SUBSEQUENT trivial sequential read
RA_PATTERN_CONTEXT interleaved sequential read
RA_PATTERN_OVERSIZE oversize read
RA_PATTERN_MMAP_AROUND mmap fault
RA_PATTERN_FADVISE posix_fadvise()
RA_PATTERN_RANDOM random read

Note that random reads will be recorded in file_ra_state now. This won't deteriorate cache bouncing because the ra->prev_pos update in do_generic_file_read() already pollutes the data cache, and filemap_fault() will stop calling into us after MMAP_LOTSAMISS.

---
 include/linux/fs.h |   33 +++++++++++++++++++++++++++++++++
 include/linux/mm.h |    4 +++-
 mm/filemap.c       |    9 +++++++--
 mm/readahead.c     |   30 +++++++++++++++++++++++-------
 4 files changed, 66 insertions(+), 10 deletions(-)
include/linux/fs.h +33 -0
@@ -951,6 +951,39 @@ struct file_ra_state {
 
 /* ra_flags bits */
 #define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+#define	READAHEAD_MMAP		0x00010000
+
+#define READAHEAD_PATTERN_SHIFT	28
+#define READAHEAD_PATTERN	0xf0000000
+
+/*
+ * Which policy makes decision to do the current read-ahead IO?
+ */
+enum readahead_pattern {
+	RA_PATTERN_INITIAL,
+	RA_PATTERN_SUBSEQUENT,
+	RA_PATTERN_CONTEXT,
+	RA_PATTERN_MMAP_AROUND,
+	RA_PATTERN_FADVISE,
+	RA_PATTERN_OVERSIZE,
+	RA_PATTERN_RANDOM,
+	RA_PATTERN_ALL,		/* for summary stats */
+	RA_PATTERN_MAX
+};
+
+static inline unsigned int ra_pattern(unsigned int ra_flags)
+{
+	unsigned int pattern = ra_flags >> READAHEAD_PATTERN_SHIFT;
+
+	return min_t(unsigned int, pattern, RA_PATTERN_ALL);
+}
+
+static inline void ra_set_pattern(struct file_ra_state *ra,
+				  unsigned int pattern)
+{
+	ra->ra_flags = (ra->ra_flags & ~READAHEAD_PATTERN) |
+			    (pattern << READAHEAD_PATTERN_SHIFT);
+}
 
 /*
  * Don't do ra_flags++ directly to avoid possible overflow:
mm/readahead.c +23 -7
@@ -268,13 +268,17 @@ unsigned long max_sane_readahead(unsigne
  * Submit IO for the read-ahead request in file_ra_state.
  */
 unsigned long ra_submit(struct file_ra_state *ra,
-		       struct address_space *mapping, struct file *filp)
+			struct address_space *mapping,
+			struct file *filp,
+			pgoff_t offset,
+			unsigned long req_size)
 {
 	int actual;
 
 	actual = __do_page_cache_readahead(mapping, filp,
 					ra->start, ra->size, ra->async_size);
 
+	ra->ra_flags &= ~READAHEAD_MMAP;
 	return actual;
 }
 
@@ -401,6 +405,7 @@ static int try_context_readahead(struct 
 	if (size >= offset)
 		size *= 2;
 
+	ra_set_pattern(ra, RA_PATTERN_CONTEXT);
 	ra->start = offset;
 	ra->size = get_init_ra_size(size + req_size, max);
 	ra->async_size = ra->size;
@@ -422,8 +427,10 @@ ondemand_readahead(struct address_space 
 	/*
 	 * start of file
 	 */
-	if (!offset)
+	if (!offset) {
+		ra_set_pattern(ra, RA_PATTERN_INITIAL);
 		goto initial_readahead;
+	}
 
 	/*
 	 * It's the expected callback offset, assume sequential access.
@@ -431,6 +438,7 @@ ondemand_readahead(struct address_space 
 	 */
 	if ((offset == (ra->start + ra->size - ra->async_size) ||
 	     offset == (ra->start + ra->size))) {
+		ra_set_pattern(ra, RA_PATTERN_SUBSEQUENT);
 		ra->start += ra->size;
 		ra->size = get_next_ra_size(ra, max);
 		ra->async_size = ra->size;
@@ -453,6 +461,7 @@ ondemand_readahead(struct address_space 
 		if (!start || start - offset > max)
 			return 0;
 
+		ra_set_pattern(ra, RA_PATTERN_CONTEXT);
 		ra->start = start;
 		ra->size = start - offset;	/* old async_size */
 		ra->size += req_size;
@@ -464,14 +473,18 @@ ondemand_readahead(struct address_space 
 	/*
 	 * oversize read
 	 */
-	if (req_size > max)
+	if (req_size > max) {
+		ra_set_pattern(ra, RA_PATTERN_OVERSIZE);
 		goto initial_readahead;
+	}
 
 	/*
 	 * sequential cache miss
 	 */
-	if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL)
+	if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) {
+		ra_set_pattern(ra, RA_PATTERN_INITIAL);
 		goto initial_readahead;
+	}
 
 	/*
 	 * Query the page cache and look for the traces(cached history pages)
@@ -482,9 +495,12 @@ ondemand_readahead(struct address_space 
 
 	/*
 	 * standalone, small random read
-	 * Read as is, and do not pollute the readahead state.
 	 */
-	return __do_page_cache_readahead(mapping, filp, offset, req_size, 0);
+	ra_set_pattern(ra, RA_PATTERN_RANDOM);
+	ra->start = offset;
+	ra->size = req_size;
+	ra->async_size = 0;
+	goto readit;
 
 initial_readahead:
 	ra->start = offset;
@@ -502,7 +518,7 @@ readit:
 		ra->size += ra->async_size;
 	}
 
-	return ra_submit(ra, mapping, filp);
+	return ra_submit(ra, mapping, filp, offset, req_size);
 }
 
 /**
include/linux/mm.h +3 -1
@@ -1456,7 +1456,9 @@ void page_cache_async_readahead(struct a
 unsigned long max_sane_readahead(unsigned long nr);
 unsigned long ra_submit(struct file_ra_state *ra,
 			struct address_space *mapping,
-			struct file *filp);
+			struct file *filp,
+			pgoff_t offset,
+			unsigned long req_size);
 
 /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
mm/filemap.c +7 -2
@@ -1592,6 +1592,7 @@ static void do_sync_mmap_readahead(struc
 		return;
 
 	if (VM_SequentialReadHint(vma)) {
+		ra->ra_flags |= READAHEAD_MMAP;
 		page_cache_sync_readahead(mapping, ra, file, offset,
 					  ra->ra_pages);
 		return;
@@ -1607,11 +1608,13 @@ static void do_sync_mmap_readahead(struc
 	/*
 	 * mmap read-around
 	 */
+	ra->ra_flags |= READAHEAD_MMAP;
+	ra_set_pattern(ra, RA_PATTERN_MMAP_AROUND);
 	ra_pages = max_sane_readahead(ra->ra_pages);
 	ra->start = max_t(long, 0, offset - ra_pages / 2);
 	ra->size = ra_pages;
 	ra->async_size = ra_pages / 4;
-	ra_submit(ra, mapping, file);
+	ra_submit(ra, mapping, file, offset, 1);
 }
 
 /*
@@ -1630,9 +1633,11 @@ static void do_async_mmap_readahead(stru
 	if (VM_RandomReadHint(vma))
 		return;
 	ra_mmap_miss_dec(ra);
-	if (PageReadahead(page))
+	if (PageReadahead(page)) {
+		ra->ra_flags |= READAHEAD_MMAP;
 		page_cache_async_readahead(mapping, ra, file,
 					   page, offset, ra->ra_pages);
+	}
 }
 
 /**

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#28 lore raw

Re: [PATCH 4/8] readahead: record readahead patterns

Quoted 5 lines · On Mon, 21 Nov 2011 17:18:23 +0800 Wu Fengguang <[email protected]> wrote:

Record the readahead pattern in ra_flags and extend the ra_submit() parameters, to be used by the next readahead tracing/stats patches.

7 patterns are defined:

Quoted 9 lines

pattern readahead for
-----------------------------------------------------------
RA_PATTERN_INITIAL start-of-file read
RA_PATTERN_SUBSEQUENT trivial sequential read
RA_PATTERN_CONTEXT interleaved sequential read
RA_PATTERN_OVERSIZE oversize read
RA_PATTERN_MMAP_AROUND mmap fault
RA_PATTERN_FADVISE posix_fadvise()
RA_PATTERN_RANDOM random read

It would be useful to spell out in full detail what an "interleaved sequential read" is, and why a read is considered "oversized", etc. The 'enum readahead_pattern' definition site would be a good place for this.

include/linux/fs.h struct file_ra_state { · line 954

Quoted 12 lines

Note that random reads will be recorded in file_ra_state now. This won't deteriorate cache bouncing because the ra->prev_pos update in do_generic_file_read() already pollutes the data cache, and filemap_fault() will stop calling into us after MMAP_LOTSAMISS.

include/linux/fs.h +1 -0
@@ -951,6 +951,39 @@ struct file_ra_state {
 
 /* ra_flags bits */
 #define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+#define	READAHEAD_MMAP		0x00010000

Why leave a gap?

And what is READAHEAD_MMAP anyway?

include/linux/fs.h struct file_ra_state { · line 956

Quoted 1 line
include/linux/fs.h +1 -0
+#define READAHEAD_PATTERN_SHIFT	28

Why 28?

Quoted 6 lines
include/linux/fs.h +6 -0
+#define READAHEAD_PATTERN	0xf0000000
+
+/*
+ * Which policy makes decision to do the current read-ahead IO?
+ */
+enum readahead_pattern {

include/linux/fs.h struct file_ra_state { · line 972

Quoted 10 lines
include/linux/fs.h +10 -0
+	RA_PATTERN_INITIAL,
+	RA_PATTERN_SUBSEQUENT,
+	RA_PATTERN_CONTEXT,
+	RA_PATTERN_MMAP_AROUND,
+	RA_PATTERN_FADVISE,
+	RA_PATTERN_OVERSIZE,
+	RA_PATTERN_RANDOM,
+	RA_PATTERN_ALL,		/* for summary stats */
+	RA_PATTERN_MAX
+};

Again, the behaviour is all undocumented. I see from the code that multiple flags can be set at the same time. So afacit a file can be marked RANDOM and SUBSEQUENT at the same time, which seems oxymoronic.

This reader wants to know what the implications of this are - how the code chooses, prioritises and acts. But this code doesn't tell me.

include/linux/fs.h struct file_ra_state { · line 976

Quoted 3 lines
include/linux/fs.h +3 -0
+static inline unsigned int ra_pattern(unsigned int ra_flags)
+{
+	unsigned int pattern = ra_flags >> READAHEAD_PATTERN_SHIFT;

OK, no masking is needed because the code silently assumes that arg `ra_flags' came out of an ra_state.ra_flags and it also silently assumes that no higher bits are used in ra_state.ra_flags.

That's a bit of a handgrenade - if someone redoes the flags enumeration, the code will explode.

include/linux/fs.h struct file_ra_state { · line 976

Quoted 2 lines
include/linux/fs.h +2 -0
+	return min_t(unsigned int, pattern, RA_PATTERN_ALL);
+}

<scratches head>

What the heck is that min_t() doing in there?

include/linux/fs.h struct file_ra_state {

Quoted 12 lines
include/linux/fs.h +6 -0
+static inline void ra_set_pattern(struct file_ra_state *ra,
+				  unsigned int pattern)
+{
+	ra->ra_flags = (ra->ra_flags & ~READAHEAD_PATTERN) |
+			    (pattern << READAHEAD_PATTERN_SHIFT);
+}
 
 /*
  * Don't do ra_flags++ directly to avoid possible overflow:
 
...

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#29 lore raw

Re: [PATCH 4/8] readahead: record readahead patterns

Quoted 18 lines · Andrew Morton
Quoted 5 lines · On Mon, 21 Nov 2011 17:18:23 +0800 Wu Fengguang <[email protected]> wrote:

Record the readahead pattern in ra_flags and extend the ra_submit() parameters, to be used by the next readahead tracing/stats patches.

7 patterns are defined:

Quoted 9 lines

pattern readahead for
-----------------------------------------------------------
RA_PATTERN_INITIAL start-of-file read
RA_PATTERN_SUBSEQUENT trivial sequential read
RA_PATTERN_CONTEXT interleaved sequential read
RA_PATTERN_OVERSIZE oversize read
RA_PATTERN_MMAP_AROUND mmap fault
RA_PATTERN_FADVISE posix_fadvise()
RA_PATTERN_RANDOM random read

Quoted 4 lines

It would be useful to spell out in full detail what an "interleaved sequential read" is, and why a read is considered "oversized", etc. The 'enum readahead_pattern' definition site would be a good place for this.

Good point, here is the added comments:

/*
* Which policy makes decision to do the current read-ahead IO? *

 * RA_PATTERN_INITIAL           readahead window is initially opened,
 *                              normally when reading from start of file
 * RA_PATTERN_SUBSEQUENT        readahead window is pushed forward
 * RA_PATTERN_CONTEXT           no readahead window available, querying the
 *                              page cache to decide readahead start/size.
 *                              This typically happens on interleaved reads (eg.
 *                              reading pages 0, 1000, 1, 1001, 2, 1002, ...)
 *                              where one file_ra_state struct is not enough
 *                              for recording 2+ interleaved sequential read
 *                              streams.
 * RA_PATTERN_MMAP_AROUND       read-around on mmap page faults
 *                              (w/o any sequential/random hints)
 * RA_PATTERN_BACKWARDS         reverse reading detected
 * RA_PATTERN_FADVISE           triggered by POSIX_FADV_WILLNEED or FMODE_RANDOM
 * RA_PATTERN_OVERSIZE          a random read larger than max readahead size,
 *                              do max readahead to break down the read size
 * RA_PATTERN_RANDOM            a small random read

*/

Quoted 9 lines
Quoted 9 lines

Note that random reads will be recorded in file_ra_state now. This won't deteriorate cache bouncing because the ra->prev_pos update in do_generic_file_read() already pollutes the data cache, and filemap_fault() will stop calling into us after MMAP_LOTSAMISS.

include/linux/fs.h +0 -0
@@ -951,6 +951,39 @@ struct file_ra_state {
 
Quoted 5 lines

include/linux/fs.h struct file_ra_state { · line 954

Quoted 3 lines
include/linux/fs.h +1 -0
 /* ra_flags bits */
 #define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
+#define	READAHEAD_MMAP		0x00010000

Why leave a gap?

Never mind, it's now converted to a bit field :)

Quoted 1 line

And what is READAHEAD_MMAP anyway?

READAHEAD_MMAP will be set for mmap page faults.

Quoted 3 lines

include/linux/fs.h struct file_ra_state { · line 956

Quoted 1 line
include/linux/fs.h +1 -0
+#define READAHEAD_PATTERN_SHIFT	28

Why 28?

Bits 28-32 are for READAHEAD_PATTERN.

Anyway it will be gone when breaking down the ra_flags fields into individual variables.

Quoted 12 lines
Quoted 12 lines
include/linux/fs.h +12 -0
+#define READAHEAD_PATTERN	0xf0000000
+
+/*
+ * Which policy makes decision to do the current read-ahead IO?
+ */
+enum readahead_pattern {
+	RA_PATTERN_INITIAL,
+	RA_PATTERN_SUBSEQUENT,
+	RA_PATTERN_CONTEXT,
+	RA_PATTERN_MMAP_AROUND,
+	RA_PATTERN_FADVISE,
+	RA_PATTERN_OVERSIZE,
Quoted 8 lines

include/linux/fs.h struct file_ra_state { · line 972

Quoted 4 lines
include/linux/fs.h +4 -0
+	RA_PATTERN_RANDOM,
+	RA_PATTERN_ALL,		/* for summary stats */
+	RA_PATTERN_MAX
+};

Again, the behaviour is all undocumented. I see from the code that multiple flags can be set at the same time. So afacit a file can be marked RANDOM and SUBSEQUENT at the same time, which seems oxymoronic.

Nope, it will be classified into one "pattern" exclusively.

Quoted 2 lines

This reader wants to know what the implications of this are - how the code chooses, prioritises and acts. But this code doesn't tell me.

Hope the comment addresses this issue. The precise logic happens mainly inside ondemand_readahead().

Quoted 10 lines

include/linux/fs.h struct file_ra_state { · line 976

Quoted 3 lines
include/linux/fs.h +3 -0
+static inline unsigned int ra_pattern(unsigned int ra_flags)
+{
+	unsigned int pattern = ra_flags >> READAHEAD_PATTERN_SHIFT;

OK, no masking is needed because the code silently assumes that arg `ra_flags' came out of an ra_state.ra_flags and it also silently assumes that no higher bits are used in ra_state.ra_flags.

That's a bit of a handgrenade - if someone redoes the flags enumeration, the code will explode.

Yeah sorry for playing with such tricks. Will get rid of this function totally and use a plain assign to ra->pattern.

Quoted 6 lines

include/linux/fs.h struct file_ra_state { · line 976

Quoted 2 lines
include/linux/fs.h +2 -0
+	return min_t(unsigned int, pattern, RA_PATTERN_ALL);
+}

<scratches head>

What the heck is that min_t() doing in there?

Just for safety... not really necessary given correct code.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#30 lore raw

PATCH 5/8 readahead: add /debug/readahead/stats

In reply to Wu Fengguang

The accounting code will be compiled in by default (CONFIG_READAHEAD_STATS=y), and will remain inactive unless enabled explicitly with either boot option

readahead_stats=1

or through the debugfs interface

echo 1 > /debug/readahead/stats_enable

The added overheads are two readahead_stats() calls per readahead. Which is trivial costs unless there are concurrent random reads on super fast SSDs, which may lead to cache bouncing when updating the global ra_stats[][]. Considering that normal users won't need this except when debugging performance problems, it's disabled by default. So it looks reasonable to keep this debug code simple rather than trying to improve its scalability.

Example output:
(taken from a fresh booted NFS-ROOT console box with rsize=524288)

$ cat /debug/readahead/stats
pattern     readahead    eof_hit  cache_hit         io    sync_io    mmap_io       size async_size    io_size
initial           545        347         10        535        535          0         74         38          3
subsequent         48         41          1         11          1          5         53         53         15
context           156        156          0          3          0          1       1690       1690         12
around            152        152          0        152        152        152       1920        480         45
backwards           2          0          2          2          2          0          4          0          3
fadvise          2566          0          0       2566          0          0          0          0          1
oversize            0          0          0          0          0          0          0          0          0
random             30          0          1         29         29          0          1          0          1
all              3499        696         14       3298        719          0        171        102          3

The two most important columns are
- io number of readahead IO
- io_size average readahead IO size

---
 Documentation/kernel-parameters.txt |    6 
 mm/Kconfig                          |   15 ++
 mm/readahead.c                      |  194 ++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
mm/readahead.c +194 -0
@@ -18,6 +18,17 @@
 #include <linux/pagevec.h>
 #include <linux/pagemap.h>
 
+static const char * const ra_pattern_names[] = {
+	[RA_PATTERN_INITIAL]            = "initial",
+	[RA_PATTERN_SUBSEQUENT]         = "subsequent",
+	[RA_PATTERN_CONTEXT]            = "context",
+	[RA_PATTERN_MMAP_AROUND]        = "around",
+	[RA_PATTERN_FADVISE]            = "fadvise",
+	[RA_PATTERN_OVERSIZE]           = "oversize",
+	[RA_PATTERN_RANDOM]             = "random",
+	[RA_PATTERN_ALL]                = "all",
+};
+
 static int __init config_readahead_size(char *str)
 {
 	unsigned long bytes;
@@ -51,6 +62,182 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
+#ifdef CONFIG_READAHEAD_STATS
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+static u32 readahead_stats_enable __read_mostly;
+
+static int __init config_readahead_stats(char *str)
+{
+	int enable = 1;
+	get_option(&str, &enable);
+	readahead_stats_enable = enable;
+	return 0;
+}
+early_param("readahead_stats", config_readahead_stats);
+
+enum ra_account {
+	/* number of readaheads */
+	RA_ACCOUNT_COUNT,	/* readahead request */
+	RA_ACCOUNT_EOF,		/* readahead request covers EOF */
+	RA_ACCOUNT_CHIT,	/* readahead request covers some cached pages */
+	RA_ACCOUNT_IOCOUNT,	/* readahead IO */
+	RA_ACCOUNT_SYNC,	/* readahead IO that is synchronous */
+	RA_ACCOUNT_MMAP,	/* readahead IO by mmap page faults */
+	/* number of readahead pages */
+	RA_ACCOUNT_SIZE,	/* readahead size */
+	RA_ACCOUNT_ASIZE,	/* readahead async size */
+	RA_ACCOUNT_ACTUAL,	/* readahead actual IO size */
+	/* end mark */
+	RA_ACCOUNT_MAX,
+};
+
+static unsigned long ra_stats[RA_PATTERN_MAX][RA_ACCOUNT_MAX];
+
+static void readahead_stats(struct address_space *mapping,
+			    pgoff_t offset,
+			    unsigned long req_size,
+			    unsigned int ra_flags,
+			    pgoff_t start,
+			    unsigned int size,
+			    unsigned int async_size,
+			    int actual)
+{
+	unsigned int pattern = ra_pattern(ra_flags);
+
+	ra_stats[pattern][RA_ACCOUNT_COUNT]++;
+	ra_stats[pattern][RA_ACCOUNT_SIZE] += size;
+	ra_stats[pattern][RA_ACCOUNT_ASIZE] += async_size;
+	ra_stats[pattern][RA_ACCOUNT_ACTUAL] += actual;
+
+	if (actual < size) {
+		if (start + size >
+		    (i_size_read(mapping->host) - 1) >> PAGE_CACHE_SHIFT)
+			ra_stats[pattern][RA_ACCOUNT_EOF]++;
+		else
+			ra_stats[pattern][RA_ACCOUNT_CHIT]++;
+	}
+
+	if (!actual)
+		return;
+
+	ra_stats[pattern][RA_ACCOUNT_IOCOUNT]++;
+
+	if (start <= offset && offset < start + size)
+		ra_stats[pattern][RA_ACCOUNT_SYNC]++;
+
+	if (ra_flags & READAHEAD_MMAP)
+		ra_stats[pattern][RA_ACCOUNT_MMAP]++;
+}
+
+static int readahead_stats_show(struct seq_file *s, void *_)
+{
+	unsigned long i;
+
+	seq_printf(s, "%-10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n",
+			"pattern",
+			"readahead", "eof_hit", "cache_hit",
+			"io", "sync_io", "mmap_io",
+			"size", "async_size", "io_size");
+
+	for (i = 0; i < RA_PATTERN_MAX; i++) {
+		unsigned long count = ra_stats[i][RA_ACCOUNT_COUNT];
+		unsigned long iocount = ra_stats[i][RA_ACCOUNT_IOCOUNT];
+		/*
+		 * avoid division-by-zero
+		 */
+		if (count == 0)
+			count = 1;
+		if (iocount == 0)
+			iocount = 1;
+
+		seq_printf(s, "%-10s %10lu %10lu %10lu %10lu %10lu %10lu "
+			   "%10lu %10lu %10lu\n",
+				ra_pattern_names[i],
+				ra_stats[i][RA_ACCOUNT_COUNT],
+				ra_stats[i][RA_ACCOUNT_EOF],
+				ra_stats[i][RA_ACCOUNT_CHIT],
+				ra_stats[i][RA_ACCOUNT_IOCOUNT],
+				ra_stats[i][RA_ACCOUNT_SYNC],
+				ra_stats[i][RA_ACCOUNT_MMAP],
+				ra_stats[i][RA_ACCOUNT_SIZE]   / count,
+				ra_stats[i][RA_ACCOUNT_ASIZE]  / count,
+				ra_stats[i][RA_ACCOUNT_ACTUAL] / iocount);
+	}
+
+	return 0;
+}
+
+static int readahead_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, readahead_stats_show, NULL);
+}
+
+static ssize_t readahead_stats_write(struct file *file, const char __user *buf,
+				     size_t size, loff_t *offset)
+{
+	memset(ra_stats, 0, sizeof(ra_stats));
+	return size;
+}
+
+static const struct file_operations readahead_stats_fops = {
+	.owner		= THIS_MODULE,
+	.open		= readahead_stats_open,
+	.write		= readahead_stats_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init readahead_create_debugfs(void)
+{
+	struct dentry *root;
+	struct dentry *entry;
+
+	root = debugfs_create_dir("readahead", NULL);
+	if (!root)
+		goto out;
+
+	entry = debugfs_create_file("stats", 0644, root,
+				    NULL, &readahead_stats_fops);
+	if (!entry)
+		goto out;
+
+	entry = debugfs_create_bool("stats_enable", 0644, root,
+				    &readahead_stats_enable);
+	if (!entry)
+		goto out;
+
+	return 0;
+out:
+	printk(KERN_ERR "readahead: failed to create debugfs entries\n");
+	return -ENOMEM;
+}
+
+late_initcall(readahead_create_debugfs);
+#endif
+
+static void readahead_event(struct address_space *mapping,
+			    pgoff_t offset,
+			    unsigned long req_size,
+			    unsigned int ra_flags,
+			    pgoff_t start,
+			    unsigned int size,
+			    unsigned int async_size,
+			    unsigned int actual)
+{
+#ifdef CONFIG_READAHEAD_STATS
+	if (readahead_stats_enable) {
+		readahead_stats(mapping, offset, req_size, ra_flags,
+				start, size, async_size, actual);
+		readahead_stats(mapping, offset, req_size,
+				RA_PATTERN_ALL << READAHEAD_PATTERN_SHIFT,
+				start, size, async_size, actual);
+	}
+#endif
+}
+
 /*
  * see if a page needs releasing upon read_cache_pages() failure
  * - the caller of read_cache_pages() may have set PG_private or PG_fscache
@@ -247,10 +434,14 @@ int force_page_cache_readahead(struct ad
 			ret = err;
 			break;
 		}
+		readahead_event(mapping, offset, nr_to_read,
+				RA_PATTERN_FADVISE << READAHEAD_PATTERN_SHIFT,
+				offset, this_chunk, 0, err);
 		ret += err;
 		offset += this_chunk;
 		nr_to_read -= this_chunk;
 	}
+
 	return ret;
 }
 
@@ -278,6 +469,9 @@ unsigned long ra_submit(struct file_ra_s
 	actual = __do_page_cache_readahead(mapping, filp,
 					ra->start, ra->size, ra->async_size);
 
+	readahead_event(mapping, offset, req_size, ra->ra_flags,
+			ra->start, ra->size, ra->async_size, actual);
+
 	ra->ra_flags &= ~READAHEAD_MMAP;
 	return actual;
 }
mm/Kconfig +15 -0
@@ -373,3 +373,18 @@ config CLEANCACHE
 	  in a negligible performance hit.
 
 	  If unsure, say Y to enable cleancache
+
+config READAHEAD_STATS
+	bool "Collect page cache readahead stats"
+	depends on DEBUG_FS
+	default y
+	help
+	  This provides the readahead events accounting facilities.
+
+	  To enable accounting early, boot kernel with "readahead_stats=1".
+	  Or run these commands after boot:
+
+	  echo 1 > /sys/kernel/debug/readahead/stats_enable
+	  echo 0 > /sys/kernel/debug/readahead/stats  # reset counters
+	  # run the workload
+	  cat /sys/kernel/debug/readahead/stats       # check counters
Documentation/kernel-parameters.txt +6 -0
@@ -2251,6 +2251,12 @@ bytes respectively. Such letter suffixes
 			This default max readahead size may be overrode
 			in some cases, notably NFS, btrfs and software RAID.
 
+	readahead_stats[=0|1]
+			Enable/disable readahead stats accounting.
+
+			It's also possible to enable/disable it after boot:
+			echo 1 > /sys/kernel/debug/readahead/stats_enable
+
 	reboot=		[BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
 			Format: <reboot_mode>[,<reboot_mode2>[,...]]
 			See arch/*/kernel/reboot.c or arch/*/kernel/process.c

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#31 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Quoted 1 line

+static unsigned long ra_stats[RA_PATTERN_MAX][RA_ACCOUNT_MAX];

Why not make it per cpu? That should get the overhead down, probably even enough that it can be enabled by default.

BTW I have an older framework to make it really easy to add per cpu stats counters to debugfs. Will repost, that would simplify it even more.

-Andi

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#32 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Andi,

Quoted 8 lines · Andi Kleen
Quoted 1 line

+static unsigned long ra_stats[RA_PATTERN_MAX][RA_ACCOUNT_MAX];

Why not make it per cpu? That should get the overhead down, probably even enough that it can be enabled by default.

BTW I have an older framework to make it really easy to add per cpu stats counters to debugfs. Will repost, that would simplify it even more.

That's definitely a good facility to have. I would be happy to become its first user :)

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#33 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

In reply to Wu Fengguang
Quoted 8 lines · On Mon, 21 Nov 2011 17:18:24 +0800 Wu Fengguang <[email protected]> wrote:

The accounting code will be compiled in by default (CONFIG_READAHEAD_STATS=y), and will remain inactive unless enabled explicitly with either boot option

readahead_stats=1

or through the debugfs interface

echo 1 > /debug/readahead/stats_enable

It's unfortunate that these two things have different names.

I'd have thought that the debugfs knob was sufficient - no need for the boot option.

Quoted 7 lines

The added overheads are two readahead_stats() calls per readahead. Which is trivial costs unless there are concurrent random reads on super fast SSDs, which may lead to cache bouncing when updating the global ra_stats[][]. Considering that normal users won't need this except when debugging performance problems, it's disabled by default. So it looks reasonable to keep this debug code simple rather than trying to improve its scalability.

I may be wrong, but I don't think the CPU cost of this code matters a lot. People will rarely turn it on and disk IO is a lot slower than CPU actions and it's waaaaaaay more important to get high-quality info about readahead than it is to squeeze out a few CPU cycles.

Quoted 11 lines

...

mm/readahead.c +4 -0
@@ -51,6 +62,182 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
+#ifdef CONFIG_READAHEAD_STATS
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 78

Quoted 10 lines
mm/readahead.c +10 -0
+static u32 readahead_stats_enable __read_mostly;
+
+static int __init config_readahead_stats(char *str)
+{
+	int enable = 1;
+	get_option(&str, &enable);
+	readahead_stats_enable = enable;
+	return 0;
+}
+early_param("readahead_stats", config_readahead_stats);

Why use early_param() rather than plain old __setup()?

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 84

Quoted 5 lines
mm/readahead.c +5 -0
+enum ra_account {
+	/* number of readaheads */
+	RA_ACCOUNT_COUNT,	/* readahead request */
+	RA_ACCOUNT_EOF,		/* readahead request covers EOF */
+	RA_ACCOUNT_CHIT,	/* readahead request covers some cached pages */

I don't like chit :) "cache_hit" would be better. Or just "hit".

Quoted 23 lines
mm/readahead.c +20 -0
+	RA_ACCOUNT_IOCOUNT,	/* readahead IO */
+	RA_ACCOUNT_SYNC,	/* readahead IO that is synchronous */
+	RA_ACCOUNT_MMAP,	/* readahead IO by mmap page faults */
+	/* number of readahead pages */
+	RA_ACCOUNT_SIZE,	/* readahead size */
+	RA_ACCOUNT_ASIZE,	/* readahead async size */
+	RA_ACCOUNT_ACTUAL,	/* readahead actual IO size */
+	/* end mark */
+	RA_ACCOUNT_MAX,
+};
+
 
...
 
+static void readahead_event(struct address_space *mapping,
+			    pgoff_t offset,
+			    unsigned long req_size,
+			    unsigned int ra_flags,
+			    pgoff_t start,
+			    unsigned int size,
+			    unsigned int async_size,
+			    unsigned int actual)
+{

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 132

Quoted 10 lines
mm/readahead.c +10 -0
+#ifdef CONFIG_READAHEAD_STATS
+	if (readahead_stats_enable) {
+		readahead_stats(mapping, offset, req_size, ra_flags,
+				start, size, async_size, actual);
+		readahead_stats(mapping, offset, req_size,
+				RA_PATTERN_ALL << READAHEAD_PATTERN_SHIFT,
+				start, size, async_size, actual);
+	}
+#endif
+}

The stub should be inlined, methinks. The overhead of evaluating and preparing eight arguments is significant. I don't think the compiler is yet smart enough to save us.

Quoted 6 lines

...

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes · line 2258

Quoted 8 lines
Documentation/kernel-parameters.txt +5 -0
@@ -2251,6 +2251,12 @@ bytes respectively. Such letter suffixes
 			This default max readahead size may be overrode
 			in some cases, notably NFS, btrfs and software RAID.
 
+	readahead_stats[=0|1]
+			Enable/disable readahead stats accounting.
+
+			It's also possible to enable/disable it after boot:
+			echo 1 > /sys/kernel/debug/readahead/stats_enable

Can the current setting be read back?

#34 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Quoted 4 lines

I may be wrong, but I don't think the CPU cost of this code matters a lot. People will rarely turn it on and disk IO is a lot slower than CPU actions and it's waaaaaaay more important to get high-quality info about readahead than it is to squeeze out a few CPU cycles.

In its current form it would cache line bounce, which tends to be extremly slow. But the solution is probably to make it per CPU.

-Andi

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#35 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

In reply to Andrew Morton
Quoted 6 lines · Andrew Morton
Quoted 3 lines · On Mon, 21 Nov 2011 17:18:24 +0800 Wu Fengguang <[email protected]> wrote:

The accounting code will be compiled in by default (CONFIG_READAHEAD_STATS=y), and will remain inactive unless enabled explicitly with either boot option

Quoted 7 lines
Quoted 5 lines

readahead_stats=1

or through the debugfs interface

echo 1 > /debug/readahead/stats_enable

It's unfortunate that these two things have different names.

Yes unfortunately.

Quoted 2 lines

I'd have thought that the debugfs knob was sufficient - no need for the boot option.

The boot option intents to catch the boot time readaheads. However it's not that big deal, I'll drop the boot option.

Quoted 8 lines
Quoted 7 lines

The added overheads are two readahead_stats() calls per readahead. Which is trivial costs unless there are concurrent random reads on super fast SSDs, which may lead to cache bouncing when updating the global ra_stats[][]. Considering that normal users won't need this except when debugging performance problems, it's disabled by default. So it looks reasonable to keep this debug code simple rather than trying to improve its scalability.

Quoted 4 lines

I may be wrong, but I don't think the CPU cost of this code matters a lot. People will rarely turn it on and disk IO is a lot slower than CPU actions and it's waaaaaaay more important to get high-quality info about readahead than it is to squeeze out a few CPU cycles.

Agreed in general.

Quoted 4 lines
Quoted 4 lines
mm/readahead.c +0 -0
@@ -51,6 +62,182 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
Quoted 16 lines
Quoted 4 lines
mm/readahead.c +4 -0
+#ifdef CONFIG_READAHEAD_STATS
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 78

Quoted 10 lines
mm/readahead.c +10 -0
+static u32 readahead_stats_enable __read_mostly;
+
+static int __init config_readahead_stats(char *str)
+{
+	int enable = 1;
+	get_option(&str, &enable);
+	readahead_stats_enable = enable;
+	return 0;
+}
+early_param("readahead_stats", config_readahead_stats);

Why use early_param() rather than plain old __setup()?

Heh it's a no-brain copy from other code ;) Anyway, the readahead_stats boot parameter will be dropped.

Quoted 7 lines

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 84

Quoted 5 lines
mm/readahead.c +5 -0
+enum ra_account {
+	/* number of readaheads */
+	RA_ACCOUNT_COUNT,	/* readahead request */
+	RA_ACCOUNT_EOF,		/* readahead request covers EOF */
+	RA_ACCOUNT_CHIT,	/* readahead request covers some cached pages */

I don't like chit :) "cache_hit" would be better. Or just "hit".

Yeah it's not good. I renamed it to RA_ACCOUNT_CACHE_HIT.

Quoted 1 line

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 90

Quoted 1 line
mm/readahead.c +1 -0
+	RA_ACCOUNT_ASIZE,	/* readahead async size */

Also renamed that to RA_ACCOUNT_ASYNC_SIZE.

Quoted 23 lines
Quoted 23 lines
mm/readahead.c +20 -0
+	RA_ACCOUNT_ACTUAL,	/* readahead actual IO size */
+	/* end mark */
+	RA_ACCOUNT_MAX,
+};
+
 
...
 
+static void readahead_event(struct address_space *mapping,
+			    pgoff_t offset,
+			    unsigned long req_size,
+			    unsigned int ra_flags,
+			    pgoff_t start,
+			    unsigned int size,
+			    unsigned int async_size,
+			    unsigned int actual)
+{
+#ifdef CONFIG_READAHEAD_STATS
+	if (readahead_stats_enable) {
+		readahead_stats(mapping, offset, req_size, ra_flags,
+				start, size, async_size, actual);
+		readahead_stats(mapping, offset, req_size,
+				RA_PATTERN_ALL << READAHEAD_PATTERN_SHIFT,
Quoted 8 lines

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 239

Quoted 4 lines
mm/readahead.c +4 -0
+				start, size, async_size, actual);
+	}
+#endif
+}

The stub should be inlined, methinks. The overhead of evaluating and preparing eight arguments is significant. I don't think the compiler is yet smart enough to save us.

The parameter list actually becomes even out of control when doing the bit fields:

+ readahead_event(mapping, offset, req_size,

+                       ra->pattern, ra->for_mmap, ra->for_metadata,
+                       ra->start + ra->size >= eof,
+                       ra->start, ra->size, ra->async_size, actual);

So I end up passing file_ra_state around. The added cost is, I'll have to dynamically create a file_ra_state for the fadvise case, which should be acceptable since it's a cold path.

Quoted 9 lines
Quoted 9 lines

...

Documentation/kernel-parameters.txt +0 -0
@@ -2251,6 +2251,12 @@ bytes respectively. Such letter suffixes
 			This default max readahead size may be overrode
 			in some cases, notably NFS, btrfs and software RAID.
 
Quoted 7 lines

Documentation/kernel-parameters.txt bytes respectively. Such letter suffixes · line 2258

Quoted 5 lines
Documentation/kernel-parameters.txt +5 -0
+	readahead_stats[=0|1]
+			Enable/disable readahead stats accounting.
+
+			It's also possible to enable/disable it after boot:
+			echo 1 > /sys/kernel/debug/readahead/stats_enable

Can the current setting be read back?

Yes. This is possible:

echo 0 > /sys/kernel/debug/readahead/stats_enable

Thanks,
Fengguang

maintainer
#36 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Quoted 24 lines · On Tue, 29 Nov 2011 11:23:23 +0800 Wu Fengguang <[email protected]> wrote:
Quoted 7 lines
Quoted 7 lines
mm/readahead.c +7 -0
+{
+#ifdef CONFIG_READAHEAD_STATS
+	if (readahead_stats_enable) {
+		readahead_stats(mapping, offset, req_size, ra_flags,
+				start, size, async_size, actual);
+		readahead_stats(mapping, offset, req_size,
+				RA_PATTERN_ALL << READAHEAD_PATTERN_SHIFT,
Quoted 8 lines

mm/readahead.c EXPORT_SYMBOL_GPL(file_ra_state_init); · line 239

Quoted 4 lines
mm/readahead.c +4 -0
+				start, size, async_size, actual);
+	}
+#endif
+}

The stub should be inlined, methinks. The overhead of evaluating and preparing eight arguments is significant. I don't think the compiler is yet smart enough to save us.

The parameter list actually becomes even out of control when doing the bit fields:

(quoted diff) +4 -0
+       readahead_event(mapping, offset, req_size,
+                       ra->pattern, ra->for_mmap, ra->for_metadata,
+                       ra->start + ra->size >= eof,
+                       ra->start, ra->size, ra->async_size, actual);
Quoted 3 lines

So I end up passing file_ra_state around. The added cost is, I'll have to dynamically create a file_ra_state for the fadvise case, which should be acceptable since it's a cold path.

That will reduce the cost of something which would have zero cost by making this function a static inline when CONFIG_READAHEAD_STATS=n.

author Acked-by Rik van Riel
#37 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Quoted 26 lines · Andrew Morton
Quoted 24 lines · On Tue, 29 Nov 2011 11:23:23 +0800 Wu Fengguang <[email protected]> wrote:
Quoted 7 lines
Quoted 7 lines
(quoted diff) +7 -0
+{
+#ifdef CONFIG_READAHEAD_STATS
+	if (readahead_stats_enable) {
+		readahead_stats(mapping, offset, req_size, ra_flags,
+				start, size, async_size, actual);
+		readahead_stats(mapping, offset, req_size,
+				RA_PATTERN_ALL << READAHEAD_PATTERN_SHIFT,
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+				start, size, async_size, actual);
+	}
+#endif
+}

The stub should be inlined, methinks. The overhead of evaluating and preparing eight arguments is significant. I don't think the compiler is yet smart enough to save us.

The parameter list actually becomes even out of control when doing the bit fields:

(quoted diff) +4 -0
+       readahead_event(mapping, offset, req_size,
+                       ra->pattern, ra->for_mmap, ra->for_metadata,
+                       ra->start + ra->size >= eof,
+                       ra->start, ra->size, ra->async_size, actual);
Quoted 6 lines
Quoted 3 lines

So I end up passing file_ra_state around. The added cost is, I'll have to dynamically create a file_ra_state for the fadvise case, which should be acceptable since it's a cold path.

That will reduce the cost of something which would have zero cost by making this function a static inline when CONFIG_READAHEAD_STATS=n.

What I do now is to remove the readahead_event() function altogether, as done by the below patch.

Do you suggest to remove fadvise_ra and still passing the many raw values to readahead_stats()? (need to restore the inline function readahead_event() because there will be two call sites)

Thanks,
Fengguang
---
Subject: readahead: add /debug/readahead/stats
Date: Sun Nov 20 11:25:50 CST 2011

The accounting code will be compiled in by default (CONFIG_READAHEAD_STATS=y), and will remain inactive by default.

It can be runtime enabled/disabled through the debugfs interface

echo 1 > /debug/readahead/stats_enable
echo 0 > /debug/readahead/stats_enable

The added overheads are two readahead_stats() calls per readahead. Which is trivial costs unless there are concurrent random reads on super fast SSDs, which may lead to cache bouncing when updating the global ra_stats[][]. Considering that normal users won't need this except when debugging performance problems, it's disabled by default. So it looks reasonable to keep this debug code simple rather than trying to improve its scalability.

Example output:
(taken from a fresh booted NFS-ROOT console box with rsize=524288)

$ cat /debug/readahead/stats
pattern     readahead    eof_hit  cache_hit         io    sync_io    mmap_io    meta_io       size async_size    io_size
initial           702        511          0        692        692          0          0          2          0          2
subsequent          7          0          1          7          1          1          0         23         22         23
context           160        161          0          2          0          1          0          0          0         16
around            184        184        177        184        184        184          0         58          0         53
backwards           2          0          2          2          2          0          0          4          0          3
fadvise          2593         47          8       2588       2588          0          0          1          0          1
oversize            0          0          0          0          0          0          0          0          0          0
random             45         20          0         44         44          0          0          1          0          1
all              3697        923        188       3519       3511        186          0          4          0          4

The two most important columns are
- io number of readahead IO
- io_size average readahead IO size

---
 mm/Kconfig     |   15 +++
 mm/readahead.c |  183 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 196 insertions(+), 2 deletions(-)
mm/readahead.c +181 -2
@@ -18,6 +18,17 @@
 #include <linux/pagevec.h>
 #include <linux/pagemap.h>
 
+static const char * const ra_pattern_names[] = {
+	[RA_PATTERN_INITIAL]            = "initial",
+	[RA_PATTERN_SUBSEQUENT]         = "subsequent",
+	[RA_PATTERN_CONTEXT]            = "context",
+	[RA_PATTERN_MMAP_AROUND]        = "around",
+	[RA_PATTERN_FADVISE]            = "fadvise",
+	[RA_PATTERN_OVERSIZE]           = "oversize",
+	[RA_PATTERN_RANDOM]             = "random",
+	[RA_PATTERN_ALL]                = "all",
+};
+
 /*
  * Initialise a struct file's readahead state.  Assumes that the caller has
  * memset *ra to zero.
@@ -32,6 +43,167 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
+#ifdef CONFIG_READAHEAD_STATS
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+static u32 readahead_stats_enable __read_mostly;
+
+enum ra_account {
+	/* number of readaheads */
+	RA_ACCOUNT_COUNT,	/* readahead request */
+	RA_ACCOUNT_EOF,		/* readahead request covers EOF */
+	RA_ACCOUNT_CACHE_HIT,	/* readahead request covers some cached pages */
+	RA_ACCOUNT_IOCOUNT,	/* readahead IO */
+	RA_ACCOUNT_SYNC,	/* readahead IO that is synchronous */
+	RA_ACCOUNT_MMAP,	/* readahead IO by mmap page faults */
+	RA_ACCOUNT_METADATA,	/* readahead IO on metadata */
+	/* number of readahead pages */
+	RA_ACCOUNT_SIZE,	/* readahead size */
+	RA_ACCOUNT_ASYNC_SIZE,	/* readahead async size */
+	RA_ACCOUNT_ACTUAL,	/* readahead actual IO size */
+	/* end mark */
+	RA_ACCOUNT_MAX,
+};
+
+static unsigned long ra_stats[RA_PATTERN_MAX][RA_ACCOUNT_MAX];
+
+static inline void readahead_stats(struct file_ra_state *ra,
+				   struct address_space *mapping,
+				   pgoff_t offset,
+				   unsigned long req_size,
+				   pgoff_t eof,
+				   int actual)
+{
+	enum readahead_pattern pattern = ra->pattern;
+
+recount:
+	ra_stats[pattern][RA_ACCOUNT_COUNT]++;
+	ra_stats[pattern][RA_ACCOUNT_SIZE] += ra->size;
+	ra_stats[pattern][RA_ACCOUNT_ASYNC_SIZE] += ra->async_size;
+	ra_stats[pattern][RA_ACCOUNT_ACTUAL] += actual;
+
+	if (ra->start + ra->size >= eof)
+		ra_stats[pattern][RA_ACCOUNT_EOF]++;
+	if (actual < ra->size)
+		ra_stats[pattern][RA_ACCOUNT_CACHE_HIT]++;
+
+	if (actual) {
+		ra_stats[pattern][RA_ACCOUNT_IOCOUNT]++;
+
+		if (ra->start <= offset && offset < ra->start + ra->size)
+			ra_stats[pattern][RA_ACCOUNT_SYNC]++;
+
+		if (ra->for_mmap)
+			ra_stats[pattern][RA_ACCOUNT_MMAP]++;
+		if (ra->for_metadata)
+			ra_stats[pattern][RA_ACCOUNT_METADATA]++;
+	}
+
+	if (pattern != RA_PATTERN_ALL) {
+		pattern = RA_PATTERN_ALL;
+		goto recount;
+	}
+}
+
+static int readahead_stats_show(struct seq_file *s, void *_)
+{
+	unsigned long i;
+
+	seq_printf(s,
+		   "%-10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n",
+		   "pattern", "readahead", "eof_hit", "cache_hit",
+		   "io", "sync_io", "mmap_io", "meta_io",
+		   "size", "async_size", "io_size");
+
+	for (i = 0; i < RA_PATTERN_MAX; i++) {
+		unsigned long count = ra_stats[i][RA_ACCOUNT_COUNT];
+		unsigned long iocount = ra_stats[i][RA_ACCOUNT_IOCOUNT];
+		/*
+		 * avoid division-by-zero
+		 */
+		if (count == 0)
+			count = 1;
+		if (iocount == 0)
+			iocount = 1;
+
+		seq_printf(s, "%-10s %10lu %10lu %10lu %10lu %10lu "
+			   "%10lu %10lu %10lu %10lu %10lu\n",
+				ra_pattern_names[i],
+				ra_stats[i][RA_ACCOUNT_COUNT],
+				ra_stats[i][RA_ACCOUNT_EOF],
+				ra_stats[i][RA_ACCOUNT_CACHE_HIT],
+				ra_stats[i][RA_ACCOUNT_IOCOUNT],
+				ra_stats[i][RA_ACCOUNT_SYNC],
+				ra_stats[i][RA_ACCOUNT_MMAP],
+				ra_stats[i][RA_ACCOUNT_METADATA],
+				ra_stats[i][RA_ACCOUNT_SIZE] / count,
+				ra_stats[i][RA_ACCOUNT_ASYNC_SIZE] / count,
+				ra_stats[i][RA_ACCOUNT_ACTUAL] / iocount);
+	}
+
+	return 0;
+}
+
+static int readahead_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, readahead_stats_show, NULL);
+}
+
+static ssize_t readahead_stats_write(struct file *file, const char __user *buf,
+				     size_t size, loff_t *offset)
+{
+	memset(ra_stats, 0, sizeof(ra_stats));
+	return size;
+}
+
+static const struct file_operations readahead_stats_fops = {
+	.owner		= THIS_MODULE,
+	.open		= readahead_stats_open,
+	.write		= readahead_stats_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init readahead_create_debugfs(void)
+{
+	struct dentry *root;
+	struct dentry *entry;
+
+	root = debugfs_create_dir("readahead", NULL);
+	if (!root)
+		goto out;
+
+	entry = debugfs_create_file("stats", 0644, root,
+				    NULL, &readahead_stats_fops);
+	if (!entry)
+		goto out;
+
+	entry = debugfs_create_bool("stats_enable", 0644, root,
+				    &readahead_stats_enable);
+	if (!entry)
+		goto out;
+
+	return 0;
+out:
+	printk(KERN_ERR "readahead: failed to create debugfs entries\n");
+	return -ENOMEM;
+}
+
+late_initcall(readahead_create_debugfs);
+#else
+#define readahead_stats_enable	0
+static inline void readahead_stats(struct file_ra_state *ra,
+				   struct address_space *mapping,
+				   pgoff_t offset,
+				   unsigned long req_size,
+				   pgoff_t eof,
+				   int actual)
+{
+}
+#endif
+
 /*
  * see if a page needs releasing upon read_cache_pages() failure
  * - the caller of read_cache_pages() may have set PG_private or PG_fscache
@@ -209,6 +381,9 @@ out:
 int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
 		pgoff_t offset, unsigned long nr_to_read)
 {
+	struct file_ra_state fadvice_ra = {
+		.pattern	= RA_PATTERN_FADVISE,
+	};
 	int ret = 0;
 
 	if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
@@ -222,8 +397,9 @@ int force_page_cache_readahead(struct ad
 
 		if (this_chunk > nr_to_read)
 			this_chunk = nr_to_read;
-		err = __do_page_cache_readahead(mapping, filp,
-						offset, this_chunk, 0);
+		fadvice_ra.start = offset;
+		fadvice_ra.size = this_chunk;
+		err = ra_submit(&fadvice_ra, mapping, filp, offset, nr_to_read);
 		if (err < 0) {
 			ret = err;
 			break;
@@ -267,6 +443,9 @@ unsigned long ra_submit(struct file_ra_s
 	actual = __do_page_cache_readahead(mapping, filp,
 					ra->start, ra->size, ra->async_size);
 
+	if (readahead_stats_enable)
+		readahead_stats(ra, mapping, offset, req_size, eof, actual);
+
 	ra->for_mmap = 0;
 	ra->for_metadata = 0;
 	return actual;
mm/Kconfig +15 -0
@@ -373,3 +373,18 @@ config CLEANCACHE
 	  in a negligible performance hit.
 
 	  If unsure, say Y to enable cleancache
+
+config READAHEAD_STATS
+	bool "Collect page cache readahead stats"
+	depends on DEBUG_FS
+	default y
+	help
+	  This provides the readahead events accounting facilities.
+
+	  To do readahead accounting for a workload:
+
+	  echo 1 > /sys/kernel/debug/readahead/stats_enable
+	  echo 0 > /sys/kernel/debug/readahead/stats  # reset counters
+	  # run the workload
+	  cat /sys/kernel/debug/readahead/stats       # check counters
+	  echo 0 > /sys/kernel/debug/readahead/stats_enable

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#38 lore raw

Re: [PATCH 5/8] readahead: add /debug/readahead/stats

Quoted 11 lines

int force_page_cache_readahead(struct address_space *mapping, struct file *filp,

mm/readahead.c +3 -0
 		pgoff_t offset, unsigned long nr_to_read)
 {
+	struct file_ra_state fadvice_ra = {
+		.pattern	= RA_PATTERN_FADVISE,
+	};
 	int ret = 0;
 
 	if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
@@ -222,8 +397,9 @@ int force_page_cache_readahead(struct ad
 

mm/readahead.c int force_page_cache_readahead(struct ad · line 405

Quoted 10 lines
mm/readahead.c +3 -2
 		if (this_chunk > nr_to_read)
 			this_chunk = nr_to_read;
-		err = __do_page_cache_readahead(mapping, filp,
-						offset, this_chunk, 0);
+		fadvice_ra.start = offset;
+		fadvice_ra.size = this_chunk;
+		err = ra_submit(&fadvice_ra, mapping, filp, offset, nr_to_read);
 		if (err < 0) {
 			ret = err;
 			break;

It looks that we can safely use filp->f_ra:

@@ -214,6 +386,7 @@ int force_page_cache_readahead(struct ad

        if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
                return -EINVAL;
+       filp->f_ra.pattern = RA_PATTERN_FADVISE;
        nr_to_read = max_sane_readahead(nr_to_read);
        while (nr_to_read) {
                int err;

@@ -222,8 +395,9 @@ int force_page_cache_readahead(struct ad

if (this_chunk > nr_to_read)
this_chunk = nr_to_read;
- err = __do_page_cache_readahead(mapping, filp,
- offset, this_chunk, 0);

+               filp->f_ra.start = offset;
+               filp->f_ra.size = this_chunk;
+               err = ra_submit(&filp->f_ra, mapping, filp, offset, nr_to_read);
                if (err < 0) {
                        ret = err;
                        break;

But still, it adds one more function call to the fadvise path.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#39 lore raw

PATCH 6/8 readahead: add debug tracing event

In reply to Wu Fengguang

This is very useful for verifying whether the algorithms are working to our expectaions.

Example output:

# echo 1 > /debug/tracing/events/vfs/readahead/enable
# cp test-file /dev/null
# cat /debug/tracing/trace  # trimmed output
readahead-initial(dev=0:15, ino=100177, req=0+2, ra=0+4-2, async=0) = 4
readahead-subsequent(dev=0:15, ino=100177, req=2+2, ra=4+8-8, async=1) = 8
readahead-subsequent(dev=0:15, ino=100177, req=4+2, ra=12+16-16, async=1) = 16
readahead-subsequent(dev=0:15, ino=100177, req=12+2, ra=28+32-32, async=1) = 32
readahead-subsequent(dev=0:15, ino=100177, req=28+2, ra=60+60-60, async=1) = 24
readahead-subsequent(dev=0:15, ino=100177, req=60+2, ra=120+60-60, async=1) = 0
CC Ingo Molnar <[email protected]>
CC Jens Axboe <[email protected]>
CC Steven Rostedt <[email protected]>
CC Peter Zijlstra <[email protected]>
---
 include/trace/events/vfs.h |   64 +++++++++++++++++++++++++++++++++++
 mm/readahead.c             |    5 ++
 2 files changed, 69 insertions(+)
include/trace/events/vfs.h new file +64 -0
@@ -0,0 +1,64 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vfs
+
+#if !defined(_TRACE_VFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VFS_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(readahead,
+	TP_PROTO(struct address_space *mapping,
+		 pgoff_t offset,
+		 unsigned long req_size,
+		 unsigned int ra_flags,
+		 pgoff_t start,
+		 unsigned int size,
+		 unsigned int async_size,
+		 unsigned int actual),
+
+	TP_ARGS(mapping, offset, req_size,
+		ra_flags, start, size, async_size, actual),
+
+	TP_STRUCT__entry(
+		__field(	dev_t,		dev		)
+		__field(	ino_t,		ino		)
+		__field(	pgoff_t,	offset		)
+		__field(	unsigned long,	req_size	)
+		__field(	unsigned int,	pattern		)
+		__field(	pgoff_t,	start		)
+		__field(	unsigned int,	size		)
+		__field(	unsigned int,	async_size	)
+		__field(	unsigned int,	actual		)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= mapping->host->i_sb->s_dev;
+		__entry->ino		= mapping->host->i_ino;
+		__entry->pattern	= ra_pattern(ra_flags);
+		__entry->offset		= offset;
+		__entry->req_size	= req_size;
+		__entry->start		= start;
+		__entry->size		= size;
+		__entry->async_size	= async_size;
+		__entry->actual		= actual;
+	),
+
+	TP_printk("readahead-%s(dev=%d:%d, ino=%lu, "
+		  "req=%lu+%lu, ra=%lu+%d-%d, async=%d) = %d",
+			ra_pattern_names[__entry->pattern],
+			MAJOR(__entry->dev),
+			MINOR(__entry->dev),
+			__entry->ino,
+			__entry->offset,
+			__entry->req_size,
+			__entry->start,
+			__entry->size,
+			__entry->async_size,
+			__entry->start > __entry->offset,
+			__entry->actual)
+);
+
+#endif /* _TRACE_VFS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
mm/readahead.c +5 -0
@@ -48,6 +48,9 @@ static int __init config_readahead_size(
 }
 early_param("readahead", config_readahead_size);
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/vfs.h>
+
 /*
  * Initialise a struct file's readahead state.  Assumes that the caller has
  * memset *ra to zero.
@@ -236,6 +239,8 @@ static void readahead_event(struct addre
 				start, size, async_size, actual);
 	}
 #endif
+	trace_readahead(mapping, offset, req_size, ra_flags,
+			start, size, async_size, actual);
 }
 
 /*

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer Acked-by on v1 6/8
#40 lore raw

Re: [PATCH 6/8] readahead: add debug tracing event

Quoted 16 lines · Wu Fengguang

plain text document attachment (readahead-tracer.patch) This is very useful for verifying whether the algorithms are working to our expectaions.

Example output:

# echo 1 > /debug/tracing/events/vfs/readahead/enable
# cp test-file /dev/null
# cat /debug/tracing/trace  # trimmed output
readahead-initial(dev=0:15, ino=100177, req=0+2, ra=0+4-2, async=0) = 4
readahead-subsequent(dev=0:15, ino=100177, req=2+2, ra=4+8-8, async=1) = 8
readahead-subsequent(dev=0:15, ino=100177, req=4+2, ra=12+16-16, async=1) = 16
readahead-subsequent(dev=0:15, ino=100177, req=12+2, ra=28+32-32, async=1) = 32
readahead-subsequent(dev=0:15, ino=100177, req=28+2, ra=60+60-60, async=1) = 24
readahead-subsequent(dev=0:15, ino=100177, req=60+2, ra=120+60-60, async=1) = 0
Quoted 3 lines
CC Ingo Molnar <[email protected]>
CC Jens Axboe <[email protected]>
CC Steven Rostedt <[email protected]>

-- Steve

Quoted 3 lines
#41 lore raw

PATCH 7/8 readahead: basic support for backwards prefetching

In reply to Wu Fengguang

Add the backwards prefetching feature. It's pretty simple if we don't support async prefetching and interleaved reads.

Here is the behavior with an 8-page read sequence from 10000 down to 0. (The readahead size is a bit large since it's an NFS mount.)

readahead-random(dev=0:16, ino=3948605, req=10000+8, ra=10000+8-0, async=0) = 8 readahead-backwards(dev=0:16, ino=3948605, req=9992+8, ra=9968+32-0, async=0) = 32 readahead-backwards(dev=0:16, ino=3948605, req=9960+8, ra=9840+128-0, async=0) = 128 readahead-backwards(dev=0:16, ino=3948605, req=9832+8, ra=9584+256-0, async=0) = 256 readahead-backwards(dev=0:16, ino=3948605, req=9576+8, ra=9072+512-0, async=0) = 512 readahead-backwards(dev=0:16, ino=3948605, req=9064+8, ra=8048+1024-0, async=0) = 1024 readahead-backwards(dev=0:16, ino=3948605, req=8040+8, ra=6128+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=6120+8, ra=4208+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=4200+8, ra=2288+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=2280+8, ra=368+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=360+8, ra=0+368-0, async=0) = 368

And a simple 1-page read sequence from 10000 down to 0.

readahead-random(dev=0:16, ino=3948605, req=10000+1, ra=10000+1-0, async=0) = 1 readahead-backwards(dev=0:16, ino=3948605, req=9999+1, ra=9996+4-0, async=0) = 4 readahead-backwards(dev=0:16, ino=3948605, req=9995+1, ra=9980+16-0, async=0) = 16 readahead-backwards(dev=0:16, ino=3948605, req=9979+1, ra=9916+64-0, async=0) = 64 readahead-backwards(dev=0:16, ino=3948605, req=9915+1, ra=9660+256-0, async=0) = 256 readahead-backwards(dev=0:16, ino=3948605, req=9659+1, ra=9148+512-0, async=0) = 512 readahead-backwards(dev=0:16, ino=3948605, req=9147+1, ra=8124+1024-0, async=0) = 1024 readahead-backwards(dev=0:16, ino=3948605, req=8123+1, ra=6204+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=6203+1, ra=4284+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=4283+1, ra=2364+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=2363+1, ra=444+1920-0, async=0) = 1920 readahead-backwards(dev=0:16, ino=3948605, req=443+1, ra=0+444-0, async=0) = 444

CC Andi Kleen <[email protected]>
CC Li Shaohua <[email protected]>
---
 include/linux/fs.h |    1 +
 mm/readahead.c     |   14 ++++++++++++++
 2 files changed, 15 insertions(+)
include/linux/fs.h +1 -0
@@ -964,6 +964,7 @@ enum readahead_pattern {
 	RA_PATTERN_SUBSEQUENT,
 	RA_PATTERN_CONTEXT,
 	RA_PATTERN_MMAP_AROUND,
+	RA_PATTERN_BACKWARDS,
 	RA_PATTERN_FADVISE,
 	RA_PATTERN_OVERSIZE,
 	RA_PATTERN_RANDOM,
mm/readahead.c +14 -0
@@ -23,6 +23,7 @@ static const char * const ra_pattern_nam
 	[RA_PATTERN_SUBSEQUENT]         = "subsequent",
 	[RA_PATTERN_CONTEXT]            = "context",
 	[RA_PATTERN_MMAP_AROUND]        = "around",
+	[RA_PATTERN_BACKWARDS]          = "backwards",
 	[RA_PATTERN_FADVISE]            = "fadvise",
 	[RA_PATTERN_OVERSIZE]           = "oversize",
 	[RA_PATTERN_RANDOM]             = "random",
@@ -686,6 +687,19 @@ ondemand_readahead(struct address_space 
 	}
 
 	/*
+	 * backwards reading
+	 */
+	if (offset < ra->start && offset + req_size >= ra->start) {
+		ra_set_pattern(ra, RA_PATTERN_BACKWARDS);
+		ra->size = get_next_ra_size(ra, max);
+		if (ra->size > ra->start)
+			ra->size = ra->start;
+		ra->async_size = 0;
+		ra->start -= ra->size;
+		goto readit;
+	}
+
+	/*
 	 * Query the page cache and look for the traces(cached history pages)
 	 * that a sequential stream would leave behind.
 	 */

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#42 lore raw

Re: [PATCH 7/8] readahead: basic support for backwards prefetching

Quoted 2 lines · On Mon, 21 Nov 2011 17:18:26 +0800 Wu Fengguang <[email protected]> wrote:

Add the backwards prefetching feature. It's pretty simple if we don't support async prefetching and interleaved reads.

Well OK, but I wonder how many applications out there read files in reverse order. Is it common enough to bother special-casing in the kernel like this?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#43 lore raw

Re: [PATCH 7/8] readahead: basic support for backwards prefetching

Quoted 9 lines · Andrew Morton
Quoted 2 lines · On Mon, 21 Nov 2011 17:18:26 +0800 Wu Fengguang <[email protected]> wrote:

Add the backwards prefetching feature. It's pretty simple if we don't support async prefetching and interleaved reads.

Well OK, but I wonder how many applications out there read files in reverse order. Is it common enough to bother special-casing in the kernel like this?

Maybe not so many applications, but sure there are some real cases somewhere. I remember an IBM paper (that's many years ago, so cannot recall the exact title) on database shows a graph containing backwards reading curves among the other ones.

Recently Shaohua even run into a performance regression caused by glibc optimizing memcpy to access page in reverse order (15, 14, 13, ... 0).

Well this patch may not be the most pertinent fix to that particular issue. But you see the opportunity such access patterns arise from surprised areas.

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#44 lore raw

PATCH 8/8 readahead: dont do start-of-file readahead after lseek()

In reply to Wu Fengguang

Some applications (eg. blkid, id3tool etc.) seek around the file to get information. For example, blkid does

	     seek to	0
	     read	1024
	     seek to	1536
	     read	16384

The start-of-file readahead heuristic is wrong for them, whose access pattern can be identified by lseek() calls.

So test-and-set a READAHEAD_LSEEK flag on lseek() and don't do start-of-file readahead on seeing it. Proposed by Linus.

---
 fs/read_write.c    |    4 ++++
 include/linux/fs.h |    1 +
 mm/readahead.c     |    3 +++
 3 files changed, 8 insertions(+)
mm/readahead.c +3 -0
@@ -629,6 +629,8 @@ ondemand_readahead(struct address_space 
 	 * start of file
 	 */
 	if (!offset) {
+		if ((ra->ra_flags & READAHEAD_LSEEK) && req_size < max)
+			goto random_read;
 		ra_set_pattern(ra, RA_PATTERN_INITIAL);
 		goto initial_readahead;
 	}
@@ -707,6 +709,7 @@ ondemand_readahead(struct address_space 
 	if (try_context_readahead(mapping, ra, offset, req_size, max))
 		goto readit;
 
+random_read:
 	/*
 	 * standalone, small random read
 	 */
fs/read_write.c +4 -0
@@ -47,6 +47,10 @@ static loff_t lseek_execute(struct file 
 		file->f_pos = offset;
 		file->f_version = 0;
 	}
+
+	if (!(file->f_ra.ra_flags & READAHEAD_LSEEK))
+		file->f_ra.ra_flags |= READAHEAD_LSEEK;
+
 	return offset;
 }
 
include/linux/fs.h +1 -0
@@ -952,6 +952,7 @@ struct file_ra_state {
 /* ra_flags bits */
 #define	READAHEAD_MMAP_MISS	0x000003ff /* cache misses for mmap access */
 #define	READAHEAD_MMAP		0x00010000
+#define	READAHEAD_LSEEK		0x00020000 /* be conservative after lseek() */
 
 #define READAHEAD_PATTERN_SHIFT	28
 #define READAHEAD_PATTERN	0xf0000000

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#45 lore raw

Re: [PATCH 8/8] readahead: dont do start-of-file readahead after lseek()

Quoted 10 lines · On Mon, 21 Nov 2011 17:18:27 +0800 Wu Fengguang <[email protected]> wrote:

Some applications (eg. blkid, id3tool etc.) seek around the file to get information. For example, blkid does

	     seek to	0
	     read	1024
	     seek to	1536
	     read	16384

The start-of-file readahead heuristic is wrong for them, whose access pattern can be identified by lseek() calls.

ah, there we are.

Quoted 31 lines
---
 fs/read_write.c    |    4 ++++
 include/linux/fs.h |    1 +
 mm/readahead.c     |    3 +++
 3 files changed, 8 insertions(+)
mm/readahead.c +3 -0
@@ -629,6 +629,8 @@ ondemand_readahead(struct address_space 
 	 * start of file
 	 */
 	if (!offset) {
+		if ((ra->ra_flags & READAHEAD_LSEEK) && req_size < max)
+			goto random_read;
 		ra_set_pattern(ra, RA_PATTERN_INITIAL);
 		goto initial_readahead;
 	}
@@ -707,6 +709,7 @@ ondemand_readahead(struct address_space 
 	if (try_context_readahead(mapping, ra, offset, req_size, max))
 		goto readit;
 
+random_read:
 	/*
 	 * standalone, small random read
 	 */

fs/read_write.c static loff_t lseek_execute(struct file · line 55

Quoted 9 lines
fs/read_write.c +4 -0
@@ -47,6 +47,10 @@ static loff_t lseek_execute(struct file 
 		file->f_pos = offset;
 		file->f_version = 0;
 	}
+
+	if (!(file->f_ra.ra_flags & READAHEAD_LSEEK))
+		file->f_ra.ra_flags |= READAHEAD_LSEEK;
+
 	return offset;
 }

Confused. How does READAHEAD_LSEEK get cleared again?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#46 lore raw

Re: [PATCH 8/8] readahead: dont do start-of-file readahead after lseek()

Quoted 6 lines
Quoted 6 lines
fs/read_write.c +0 -0
@@ -47,6 +47,10 @@ static loff_t lseek_execute(struct file 
 		file->f_pos = offset;
 		file->f_version = 0;
 	}
Quoted 8 lines

fs/read_write.c static loff_t lseek_execute(struct file · line 55

Quoted 6 lines
fs/read_write.c +4 -0
+
+	if (!(file->f_ra.ra_flags & READAHEAD_LSEEK))
+		file->f_ra.ra_flags |= READAHEAD_LSEEK;
+
 	return offset;
 }

Confused. How does READAHEAD_LSEEK get cleared again?

I thought it's not necessary (at least for this case). But yeah, it's good to clear it to make it more reasonable and avoid unexpected things.

And it would be simple to do, in ra_submit():

- ra->ra_flags &= ~READAHEAD_MMAP;
+ ra->ra_flags &= ~(READAHEAD_MMAP | READAHEAD_LSEEK);

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#47 lore raw
In reply to Wu Fengguang
Quoted 8 lines · Wu Fengguang

Andrew,

I'm getting around to pick up the readahead works again :-)

This first series is mainly to add some debug facilities, to support the long missed backwards prefetching capability, and some old patches that somehow get delayed (shame me).

Quoted 8 lines

The next step would be to better handle the readahead thrashing situations. That would require rewriting part of the algorithms, this is why I'd like to keep the backwards prefetching simple and stupid for now.

When (almost) free of readahead thrashing, we'll be in a good position to lift the default readahead size. Which I suspect would be the single most efficient way to improve performance for the large volumes of casually maintained Linux file servers.

Btw, if you work actively in that area I have a todo list item I was planning to look into sooner or later: instead of embedding the ra state into the struct file allocate it dynamically. That way files that either don't use the pagecache, or aren't read from won't need have to pay the price for increasing struct file size, and if we have to we could enlarge it more easily. Besides removing f_version in the common struct file and also allocting f_owner separately that seem to be the easiest ways to get struct file size down.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#48 lore raw
Quoted 18 lines · Christoph Hellwig
Quoted 8 lines · Wu Fengguang

Andrew,

I'm getting around to pick up the readahead works again :-)

This first series is mainly to add some debug facilities, to support the long missed backwards prefetching capability, and some old patches that somehow get delayed (shame me).

Quoted 8 lines

The next step would be to better handle the readahead thrashing situations. That would require rewriting part of the algorithms, this is why I'd like to keep the backwards prefetching simple and stupid for now.

When (almost) free of readahead thrashing, we'll be in a good position to lift the default readahead size. Which I suspect would be the single most efficient way to improve performance for the large volumes of casually maintained Linux file servers.

Quoted 6 lines

Btw, if you work actively in that area I have a todo list item I was planning to look into sooner or later: instead of embedding the ra state into the struct file allocate it dynamically. That way files that either don't use the pagecache, or aren't read from won't need have to pay the price for increasing struct file size, and if we have to we could enlarge it more easily.

Agreed. That's good to have, please allow me to move it into my todo list :)

Quoted 3 lines

Besides removing f_version in the common
struct file and also allocting f_owner separately that seem to be the easiest ways to get struct file size down.

Yeah, there seems no much code accessing fown_struct. I may consider that when I'm at file_ra_state, but no promise ;)

Thanks,
Fengguang

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>